mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-08 17:09:51 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cce67c289a | ||
|
|
93935b1691 | ||
|
|
a13a4dc12e | ||
|
|
4fa4562bea | ||
|
|
61b86a4a9a | ||
|
|
2c70ff1291 | ||
|
|
4a3a2a7be3 | ||
|
|
2a8f9bca18 | ||
|
|
d46a67c840 | ||
|
|
043eda5bc4 | ||
|
|
a51d93cf58 | ||
|
|
44abb0e03b | ||
|
|
7ef4923fc0 | ||
|
|
3f83761a90 | ||
|
|
85265d663f |
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.16.6
|
||||
FROM golang:1.16.7
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -1038,6 +1038,9 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
LongHelp: help.GetHelpFor([]string{consts.LsStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
f.Bool("r", "reverse", false, "reverse sort order")
|
||||
f.Bool("m", "modified", false, "sort by modified time")
|
||||
f.Bool("s", "size", false, "sort by size")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("path", "path to enumerate", grumble.Default("."))
|
||||
|
||||
@@ -22,8 +22,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -40,6 +43,45 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
}
|
||||
|
||||
remotePath := ctx.Args.String("path")
|
||||
filter := ""
|
||||
|
||||
/*
|
||||
Check to see if the remote path is a filter or contains a filter.
|
||||
If the path passes the test to be a filter, then it is a filter
|
||||
because paths are not valid filters.
|
||||
*/
|
||||
if remotePath != "." {
|
||||
|
||||
// Check if the path contains a filter
|
||||
// Test on a standardized version of the path (change any \ to /)
|
||||
testPath := strings.Replace(remotePath, "\\", "/", -1)
|
||||
/*
|
||||
Cannot use the path or filepath libraries because the OS
|
||||
of the client does not necessarily match the OS of the
|
||||
implant
|
||||
*/
|
||||
lastSeparatorOccurence := strings.LastIndex(testPath, "/")
|
||||
|
||||
if lastSeparatorOccurence == -1 {
|
||||
// Then this is only a filter
|
||||
filter = remotePath
|
||||
remotePath = "."
|
||||
} else {
|
||||
// Then we need to test for a filter on the end of the string
|
||||
|
||||
// The indicies should be the same because we did not change the length of the string
|
||||
baseDir := remotePath[:lastSeparatorOccurence]
|
||||
potentialFilter := remotePath[lastSeparatorOccurence+1:]
|
||||
|
||||
_, err := filepath.Match(potentialFilter, "")
|
||||
|
||||
if err == nil {
|
||||
// Then we have a filter on the end of the path
|
||||
remotePath = baseDir
|
||||
filter = potentialFilter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ls, err := con.Rpc.Ls(context.Background(), &sliverpb.LsReq{
|
||||
Request: con.ActiveSession.Request(ctx),
|
||||
@@ -48,22 +90,92 @@ func LsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if err != nil {
|
||||
con.PrintWarnf("%s\n", err)
|
||||
} else {
|
||||
PrintLs(ls, con)
|
||||
PrintLs(ls, con, ctx.Flags, filter)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintLs - Display an sliverpb.Ls object
|
||||
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient) {
|
||||
func PrintLs(ls *sliverpb.Ls, con *console.SliverConsoleClient, flags grumble.FlagMap, filter string) {
|
||||
con.Printf("%s\n", ls.Path)
|
||||
con.Printf("%s\n", strings.Repeat("=", len(ls.Path)))
|
||||
|
||||
outputBuf := bytes.NewBufferString("")
|
||||
table := tabwriter.NewWriter(outputBuf, 0, 2, 2, ' ', 0)
|
||||
for _, fileInfo := range ls.Files {
|
||||
if fileInfo.IsDir {
|
||||
fmt.Fprintf(table, "%s\t<dir>\t\n", fileInfo.Name)
|
||||
|
||||
// Extract the flags
|
||||
reverseSort := flags.Bool("reverse")
|
||||
sortByTime := flags.Bool("modified")
|
||||
sortBySize := flags.Bool("size")
|
||||
|
||||
/*
|
||||
By default, name sorting is case sensitive. Upper case entries come before
|
||||
lower case ones. Instead, we will level the playing field and sort
|
||||
regardless of case
|
||||
*/
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return strings.ToLower(ls.Files[i].Name) > strings.ToLower(ls.Files[j].Name)
|
||||
})
|
||||
} else {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return strings.ToLower(ls.Files[i].Name) < strings.ToLower(ls.Files[j].Name)
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
After names are sorted properly, take care of the modified time if the
|
||||
user wants to sort by time. Doing this after sorting by name
|
||||
will make the time sorted entries properly sorted by name if times are equal.
|
||||
*/
|
||||
|
||||
if sortByTime {
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].ModTime > ls.Files[j].ModTime
|
||||
})
|
||||
} else {
|
||||
fmt.Fprintf(table, "%s\t%s\t\n", fileInfo.Name, util.ByteCountBinary(fileInfo.Size))
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].ModTime < ls.Files[j].ModTime
|
||||
})
|
||||
}
|
||||
} else if sortBySize {
|
||||
if reverseSort {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].Size > ls.Files[j].Size
|
||||
})
|
||||
} else {
|
||||
sort.SliceStable(ls.Files, func(i, j int) bool {
|
||||
return ls.Files[i].Size < ls.Files[j].Size
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, fileInfo := range ls.Files {
|
||||
if filter != "" {
|
||||
fileMatch, err := filepath.Match(filter, fileInfo.Name)
|
||||
|
||||
if err != nil {
|
||||
/*
|
||||
This should not happen because we checked the filter
|
||||
before reaching out to the implant.
|
||||
*/
|
||||
con.PrintErrorf("%s is not a valid filter: %s\n", filter, err)
|
||||
break
|
||||
}
|
||||
|
||||
if !fileMatch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
modTime := time.Unix(fileInfo.ModTime, 0)
|
||||
implantLocation := time.FixedZone(ls.Timezone, int(ls.TimezoneOffset))
|
||||
modTime = modTime.In(implantLocation)
|
||||
|
||||
if fileInfo.IsDir {
|
||||
fmt.Fprintf(table, "%s\t%s\t<dir>\t%s\n", fileInfo.Mode, fileInfo.Name, modTime.Format(time.RubyDate))
|
||||
} else {
|
||||
fmt.Fprintf(table, "%s\t%s\t%s\t%s\n", fileInfo.Mode, fileInfo.Name, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
|
||||
}
|
||||
}
|
||||
table.Flush()
|
||||
|
||||
@@ -235,7 +235,31 @@ c2 message round trip to ensure the remote Sliver is still responding to command
|
||||
[[.Bold]]About:[[.Normal]] Kill a remote sliver process (does not delete file).`
|
||||
|
||||
lsHelp = `[[.Bold]]Command:[[.Normal]] ls <remote path>
|
||||
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.`
|
||||
[[.Bold]]About:[[.Normal]] List remote files in current directory, or path if provided.
|
||||
|
||||
[[.Bold]][[.Underline]]Sorting[[.Normal]]
|
||||
Directory and file listings are sorted by name in ascending order by default. Listings can also be sorted by size (-s) and modified time (-m). All sorts can be reversed with -r.
|
||||
|
||||
[[.Bold]][[.Underline]]Filters[[.Normal]]
|
||||
Filters are a way to limit search results to directory and file names matching given criteria.
|
||||
|
||||
Filters are specified after the path. A blank path will filter on names in the current directory. For example:
|
||||
/etc/passwd will display the listing for /etc/passwd. "/etc/" is the path, and "passwd" is the filter.
|
||||
|
||||
Directory and file listings can be filtered using the following patterns:
|
||||
'*': Wildcard, matches any sequence of non-path separators (slashes)
|
||||
Example: n*.txt will match all file and directory names starting with n and ending with .txt
|
||||
|
||||
'?': Single character wildcard, matches a single non-path separator (slashes)
|
||||
Example: s?iver will match all file and directory names starting with s followed by any non-separator character and ending with iver.
|
||||
|
||||
'[{range}]': Match a range of characters. Ranges are specified with '-'. This is usually combined with other patterns. Ranges can be negated with '^'.
|
||||
Example: [a-c] will match the characters a, b, and c. [a-c]* will match all directory and file names that start with a, b, or c.
|
||||
^[r-u] will match all characters except r, s, t, and u.
|
||||
|
||||
If you need to match a special character (*, ?, '-', '[', ']', '\\'), place '\\' in front of it (example: \\?).
|
||||
On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
|
||||
`
|
||||
|
||||
cdHelp = `[[.Bold]]Command:[[.Normal]] cd [remote path]
|
||||
[[.Bold]]About:[[.Normal]] Change working directory of the active Sliver.`
|
||||
|
||||
@@ -2,6 +2,8 @@ package privilege
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -60,6 +62,7 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
// for column width
|
||||
var nameColumnWidth int = 0
|
||||
var descriptionColumnWidth int = 0
|
||||
var introWidth int = 49 + len(strconv.Itoa(int(session.PID)))
|
||||
|
||||
for _, entry := range privs.PrivInfo {
|
||||
if len(entry.Name) > nameColumnWidth {
|
||||
@@ -74,12 +77,13 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
nameColumnWidth += 1
|
||||
descriptionColumnWidth += 1
|
||||
|
||||
con.Println("Privilege Information for Current Process")
|
||||
con.Println("-----------------------------------------")
|
||||
con.Printf("Privilege Information for Current Process (PID: %d)\n", session.PID)
|
||||
con.Println(strings.Repeat("-", introWidth))
|
||||
con.Printf("\nProcess Integrity Level: %s\n\n", privs.ProcessIntegrity)
|
||||
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "Name", descriptionColumnWidth, "Description", "Attributes")
|
||||
con.Printf("%-*s\t%-*s\t%s\n", nameColumnWidth, "====", descriptionColumnWidth, "===========", "==========")
|
||||
for _, entry := range privs.PrivInfo {
|
||||
con.Printf("%-*s\t%-*s\t(", nameColumnWidth, entry.Name, descriptionColumnWidth, entry.Description)
|
||||
con.Printf("%-*s\t%-*s\t", nameColumnWidth, entry.Name, descriptionColumnWidth, entry.Description)
|
||||
if entry.Enabled {
|
||||
con.Printf("Enabled")
|
||||
} else {
|
||||
@@ -94,6 +98,6 @@ func GetPrivsCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
if entry.UsedForAccess {
|
||||
con.Printf(", Used for Access")
|
||||
}
|
||||
con.Printf(")\n")
|
||||
con.Printf("\n")
|
||||
}
|
||||
}
|
||||
@@ -103,8 +103,6 @@ func (tun *Tunnel) Read(data []byte) (int, error) {
|
||||
case data := <-tun.Recv:
|
||||
log.Printf("Read %d bytes", len(data))
|
||||
buff.Write(data)
|
||||
default:
|
||||
break
|
||||
}
|
||||
n := copy(data, buff.Bytes())
|
||||
return n, nil
|
||||
|
||||
+120
-24
@@ -1,15 +1,22 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SLIVER_GPG_KEY_ID=4449039C
|
||||
|
||||
if [ "$EUID" -ne 0 ]
|
||||
then echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ -n "$(command -v yum)" ]
|
||||
then
|
||||
sudo -S -p '' yum -y install zip unzip curl gcc gcc-c++ make mingw64-gcc
|
||||
yum -y install zip unzip gnupg curl gcc gcc-c++ make mingw64-gcc
|
||||
fi
|
||||
|
||||
if [ -n "$(command -v apt-get)" ]
|
||||
then
|
||||
DEBIAN_FRONTEND=noninteractive sudo -S -p '' apt-get install -yqq \
|
||||
zip unzip curl build-essential \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -yqq \
|
||||
zip unzip gpg curl build-essential \
|
||||
mingw-w64 binutils-mingw-w64 g++-mingw-w64
|
||||
fi
|
||||
|
||||
@@ -31,9 +38,69 @@ then
|
||||
echo "zip could not be found"
|
||||
exit 1
|
||||
fi
|
||||
# GPG
|
||||
if ! command -v gpg &> /dev/null
|
||||
then
|
||||
echo "gpg could not be found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $HOME
|
||||
echo "Running from $HOME"
|
||||
cd /root
|
||||
echo "Running from $(pwd)"
|
||||
|
||||
gpg --import <<EOF
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=lxj2
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
EOF
|
||||
|
||||
#
|
||||
# Download and Unpack Sliver Server
|
||||
@@ -57,44 +124,73 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
if test -f "$SLIVER_SERVER_ZIP"; then
|
||||
unzip -o $SLIVER_SERVER_ZIP -d $HOME
|
||||
rm -f $SLIVER_SERVER_ZIP
|
||||
echo "Verifying signatures ..."
|
||||
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_SERVER_ZIP.sig /root/$SLIVER_SERVER_ZIP
|
||||
gpg --default-key $SLIVER_GPG_KEY_ID --verify /root/$SLIVER_CLIENT_ZIP.sig /root/$SLIVER_CLIENT_ZIP
|
||||
|
||||
if test -f "/root/$SLIVER_SERVER_ZIP"; then
|
||||
unzip -o /root/$SLIVER_SERVER_ZIP -d /root
|
||||
rm -f /root/$SLIVER_SERVER_ZIP
|
||||
else
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if test -f "$HOME/$SLIVER_SERVER"; then
|
||||
chmod 755 $HOME/$SLIVER_SERVER
|
||||
$HOME/$SLIVER_SERVER unpack --force
|
||||
if test -f "/root/$SLIVER_SERVER"; then
|
||||
chmod 755 /root/$SLIVER_SERVER
|
||||
/root/$SLIVER_SERVER unpack --force
|
||||
else
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if test -f "$SLIVER_CLIENT_ZIP"; then
|
||||
unzip -o $SLIVER_CLIENT_ZIP -d $HOME
|
||||
rm -f $SLIVER_CLIENT_ZIP
|
||||
if test -f "/root/$SLIVER_CLIENT_ZIP"; then
|
||||
unzip -o /root/$SLIVER_CLIENT_ZIP -d /root
|
||||
rm -f /root/$SLIVER_CLIENT_ZIP
|
||||
else
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if test -f "$HOME/$SLIVER_CLIENT"; then
|
||||
chmod 755 $HOME/$SLIVER_CLIENT
|
||||
cp -vv $HOME/$SLIVER_CLIENT /usr/local/bin/sliver
|
||||
if test -f "/root/$SLIVER_CLIENT"; then
|
||||
chmod 755 /root/$SLIVER_CLIENT
|
||||
cp -vv /root/$SLIVER_CLIENT /usr/local/bin/sliver
|
||||
chmod 755 /usr/local/bin/sliver
|
||||
else
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# systemd
|
||||
curl -o ./sliver.service https://sliver.sh/sliver.service
|
||||
cp ./sliver.service /etc/systemd/system/sliver.service
|
||||
echo "Configuring systemd service ..."
|
||||
cat > /etc/systemd/system/sliver.service <<-EOF
|
||||
[Unit]
|
||||
Description=Sliver
|
||||
After=network.target
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
User=root
|
||||
ExecStart=/root/sliver-server daemon
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
chown root:root /etc/systemd/system/sliver.service
|
||||
chmod 600 /etc/systemd/system/sliver.service
|
||||
systemctl start sliver
|
||||
rm -f ./sliver.service
|
||||
|
||||
# generate local configs
|
||||
mkdir -p $HOME/.sliver-client/configs
|
||||
/root/sliver-server operator --name $USER --lhost localhost --save $HOME/.sliver-client/configs
|
||||
chown -R $USER:$USER $HOME/.sliver-client/
|
||||
# Generate local configs
|
||||
echo "Generating operator configs ..."
|
||||
mkdir -p /root/.sliver-client/configs
|
||||
/root/sliver-server operator --name root --lhost localhost --save /root/.sliver-client/configs
|
||||
chown -R root:root /root/.sliver-client/
|
||||
|
||||
USER_DIRS=(/home/*)
|
||||
for USER_DIR in "${USER_DIRS[@]}"; do
|
||||
USER=$(basename $USER_DIR)
|
||||
if id -u $USER >/dev/null 2>&1; then
|
||||
mkdir -p $USER_DIR/.sliver-client/configs
|
||||
/root/sliver-server operator --name $USER --lhost localhost --save $USER_DIR/.sliver-client/configs
|
||||
chown -R $USER:$USER $USER_DIR/.sliver-client/
|
||||
fi
|
||||
done
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.16.6"
|
||||
GO_VER="1.16.7"
|
||||
GARBLE_VER="1.16.7"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
@@ -97,7 +98,8 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
dir, files, err := getDirList(dirListReq.Path)
|
||||
|
||||
// Convert directory listing to protobuf
|
||||
dirList := &sliverpb.Ls{Path: dir}
|
||||
timezone, offset := time.Now().Zone()
|
||||
dirList := &sliverpb.Ls{Path: dir, Timezone: timezone, TimezoneOffset: int32(offset)}
|
||||
if err == nil {
|
||||
dirList.Exists = true
|
||||
} else {
|
||||
@@ -109,6 +111,13 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
Name: fileInfo.Name(),
|
||||
IsDir: fileInfo.IsDir(),
|
||||
Size: fileInfo.Size(),
|
||||
/* Send the time back to the client / server as the number of seconds
|
||||
since epoch. This will decouple formatting the time to display from the
|
||||
time itself. We can change the format of the time displayed in the client
|
||||
and not have to worry about having to update implants.
|
||||
*/
|
||||
ModTime: fileInfo.ModTime().Unix(),
|
||||
Mode: fileInfo.Mode().String(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -543,7 +543,7 @@ func getPrivsHandler(data []byte, resp RPCResponse) {
|
||||
return
|
||||
}
|
||||
|
||||
privsInfo, err := priv.GetPrivs()
|
||||
privsInfo, integrity, err := priv.GetPrivs()
|
||||
|
||||
response_data := make([]*sliverpb.WindowsPrivilegeEntry, len(privsInfo))
|
||||
|
||||
@@ -567,8 +567,9 @@ func getPrivsHandler(data []byte, resp RPCResponse) {
|
||||
|
||||
// Package up the response
|
||||
getPrivsResp := &sliverpb.GetPrivs{
|
||||
PrivInfo: response_data,
|
||||
Response: &commonpb.Response{},
|
||||
PrivInfo: response_data,
|
||||
ProcessIntegrity: integrity,
|
||||
Response: &commonpb.Response{},
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -42,7 +42,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
THREAD_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
|
||||
THREAD_ALL_ACCESS = windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xffff
|
||||
SECURITY_MANDATORY_LOW_RID = 0x00001000
|
||||
SECURITY_MANDATORY_MEDIUM_RID = 0x00002000
|
||||
SECURITY_MANDATORY_HIGH_RID = 0x00003000
|
||||
SECURITY_MANDATORY_SYSTEM_RID = 0x00004000
|
||||
)
|
||||
|
||||
type PrivilegeInfo struct {
|
||||
@@ -340,6 +344,60 @@ func GetSystem(data []byte, hostingProcess string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func getProcessIntegrityLevel(processToken syscall.Token) (string, error) {
|
||||
// A place to put the size of the token integrity information
|
||||
var tokenIntegrityBufferSize uint32
|
||||
|
||||
// Determine the integrity of the process
|
||||
syscall.GetTokenInformation(processToken, windows.TokenIntegrityLevel, nil, 0, &tokenIntegrityBufferSize)
|
||||
|
||||
if tokenIntegrityBufferSize < 4 {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("TokenIntegrityBuffer is too small (must be at least 4 bytes)")
|
||||
// {{end}}
|
||||
return "Unknown", nil
|
||||
}
|
||||
|
||||
tokenIntegrityBuffer := make([]byte, tokenIntegrityBufferSize)
|
||||
|
||||
err := syscall.GetTokenInformation(processToken,
|
||||
syscall.TokenIntegrityLevel,
|
||||
&tokenIntegrityBuffer[0],
|
||||
tokenIntegrityBufferSize,
|
||||
&tokenIntegrityBufferSize,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Error in call to GetTokenInformation (integrity): ", err)
|
||||
// {{end}}
|
||||
return "", err
|
||||
}
|
||||
|
||||
/*
|
||||
When calling GetTokenInformation with a type of TokenIntegrityLevel, the structure we get back
|
||||
is a TOKEN_MANDATORY_LABEL (https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-token_mandatory_label)
|
||||
which has one SID_AND_ATTRIBUTES structure (https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_and_attributes)
|
||||
|
||||
We need the last 4 bytes (uint32) from the structure because that contains the attributes. The attributes
|
||||
tell us what privilege level we are operating at.
|
||||
*/
|
||||
|
||||
var privilegeLevel uint32 = binary.LittleEndian.Uint32(tokenIntegrityBuffer[tokenIntegrityBufferSize-4:])
|
||||
|
||||
if privilegeLevel < SECURITY_MANDATORY_LOW_RID {
|
||||
return "Untrusted", nil
|
||||
} else if privilegeLevel < SECURITY_MANDATORY_MEDIUM_RID {
|
||||
return "Low", nil
|
||||
} else if privilegeLevel >= SECURITY_MANDATORY_MEDIUM_RID && privilegeLevel < SECURITY_MANDATORY_HIGH_RID {
|
||||
return "Medium", nil
|
||||
} else if privilegeLevel >= SECURITY_MANDATORY_HIGH_RID {
|
||||
return "High", nil
|
||||
}
|
||||
|
||||
return "Unknown", nil
|
||||
}
|
||||
|
||||
func lookupPrivilegeNameByLUID(luid uint64) (string, string, error) {
|
||||
/*
|
||||
We will need the LookupPrivilegeNameW and LookupPrivilegeDisplayNameW functions
|
||||
@@ -348,6 +406,8 @@ func lookupPrivilegeNameByLUID(luid uint64) (string, string, error) {
|
||||
|
||||
Defined these syscalls in implant/sliver/syscalls/syscalls_windows.go and generated them with
|
||||
mkwinsyscall, so we are good to go.
|
||||
|
||||
mkwinsyscall -output zsyscalls_windows.go syscalls_windows.go
|
||||
*/
|
||||
|
||||
// Allocate 256 wide unicode characters (uint16) for the both names (255 characters plus a null terminator)
|
||||
@@ -381,7 +441,7 @@ func lookupPrivilegeNameByLUID(luid uint64) (string, string, error) {
|
||||
return syscall.UTF16ToString(nameBuffer), syscall.UTF16ToString(displayNameBuffer), nil
|
||||
}
|
||||
|
||||
func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
func GetPrivs() ([]PrivilegeInfo, string, error) {
|
||||
// A place to store the process token
|
||||
var tokenHandle syscall.Token
|
||||
|
||||
@@ -395,7 +455,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not get a handle for the current process: ", err)
|
||||
// {{end}}
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Get the process token from the current process
|
||||
@@ -405,7 +465,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not open process token: ", err)
|
||||
// {{end}}
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Get the size of the token information buffer so we know how large of a buffer to allocate
|
||||
@@ -426,9 +486,9 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Error in call to GetTokenInformation: ", err)
|
||||
log.Println("Error in call to GetTokenInformation (privileges): ", err)
|
||||
// {{end}}
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// The first 32 bits is the number of privileges in the structure
|
||||
@@ -439,7 +499,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the number of privileges from the token information.")
|
||||
// {{end}}
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -468,7 +528,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the LUID from the binary stream: ", err)
|
||||
// {{end}}
|
||||
return privInfo, err
|
||||
return privInfo, "", err
|
||||
}
|
||||
|
||||
// Read the attributes
|
||||
@@ -477,7 +537,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not read the attributes from the binary stream: ", err)
|
||||
// {{end}}
|
||||
return privInfo, err
|
||||
return privInfo, "", err
|
||||
}
|
||||
|
||||
currentPrivInfo.Name, currentPrivInfo.Description, err = lookupPrivilegeNameByLUID(luid)
|
||||
@@ -485,7 +545,7 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
// {{if .Config.Debug}}
|
||||
log.Println("Could not get privilege info based on the LUID: ", err)
|
||||
// {{end}}
|
||||
return privInfo, err
|
||||
return privInfo, "", err
|
||||
}
|
||||
|
||||
// Figure out the attributes
|
||||
@@ -497,5 +557,12 @@ func GetPrivs() ([]PrivilegeInfo, error) {
|
||||
privInfo[index] = currentPrivInfo
|
||||
}
|
||||
|
||||
return privInfo, nil
|
||||
// Get the process integrity before we leave
|
||||
integrity, err := getProcessIntegrityLevel(tokenHandle)
|
||||
|
||||
if err != nil {
|
||||
return privInfo, "Could not determine integrity level", err
|
||||
}
|
||||
|
||||
return privInfo, integrity, nil
|
||||
}
|
||||
@@ -20,8 +20,6 @@ package procdump
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
//{{if .Config.Debug}}
|
||||
"log"
|
||||
//{{end}}
|
||||
@@ -31,17 +29,56 @@ import (
|
||||
"github.com/bishopfox/sliver/implant/sliver/evasion"
|
||||
// {{end}}
|
||||
// {{end}}
|
||||
"os"
|
||||
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"github.com/bishopfox/sliver/implant/sliver/priv"
|
||||
"github.com/bishopfox/sliver/implant/sliver/syscalls"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
ModuleCallback = iota
|
||||
ThreadCallback
|
||||
ThreadExCallback
|
||||
IncludeThreadCallback
|
||||
IncludeModuleCallback
|
||||
MemoryCallback
|
||||
CancelCallback
|
||||
WriteKernelMinidumpCallback
|
||||
KernelMinidumpStatusCallback
|
||||
RemoveMemoryCallback
|
||||
IncludeVmRegionCallback
|
||||
IoStartCallback
|
||||
IoWriteAllCallback
|
||||
IoFinishCallback
|
||||
ReadMemoryFailureCallback
|
||||
SecondaryFlagsCallback
|
||||
IsProcessSnapshotCallback
|
||||
VmStartCallback
|
||||
VmQueryCallback
|
||||
VmPreReadCallback
|
||||
VmPostReadCallback
|
||||
|
||||
S_FALSE = 1
|
||||
S_OK = 0
|
||||
TRUE = 1
|
||||
FALSE = 0
|
||||
IncrementSize = 5 * 1024 * 1024
|
||||
MiniDumpWithFullMemory = 0x00000002
|
||||
)
|
||||
|
||||
var bytesRead uint32 = 0
|
||||
|
||||
type WindowsDump struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
type outDump struct {
|
||||
outPtr uintptr
|
||||
}
|
||||
|
||||
func (d *WindowsDump) Data() []byte {
|
||||
return d.data
|
||||
}
|
||||
@@ -50,7 +87,7 @@ func dumpProcess(pid int32) (ProcessDump, error) {
|
||||
var lpTargetHandle windows.Handle
|
||||
res := &WindowsDump{}
|
||||
if err := priv.SePrivEnable("SeDebugPrivilege"); err != nil {
|
||||
return res, fmt.Errorf("Could not set SeDebugPrivilege on", pid)
|
||||
return res, err
|
||||
}
|
||||
|
||||
hProc, err := windows.OpenProcess(syscalls.PROCESS_DUP_HANDLE, false, uint32(pid))
|
||||
@@ -68,9 +105,7 @@ func dumpProcess(pid int32) (ProcessDump, error) {
|
||||
// {{end}}
|
||||
return res, err
|
||||
}
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if hProc != 0 {
|
||||
return minidump(uint32(pid), lpTargetHandle)
|
||||
}
|
||||
@@ -91,35 +126,188 @@ func minidump(pid uint32, proc windows.Handle) (ProcessDump, error) {
|
||||
}
|
||||
// {{end}}
|
||||
// {{end}}
|
||||
// TODO: find a better place to store the dump file
|
||||
f, err := ioutil.TempFile("", "")
|
||||
|
||||
heapHandle, err := syscalls.GetProcessHeap()
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("Failed to create temp file:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
|
||||
procMemCounters := syscalls.ProcessMemoryCounters{}
|
||||
sizeOfMemCounters := uint32(unsafe.Sizeof(procMemCounters))
|
||||
err = syscalls.GetProcessMemoryInfo(proc, &procMemCounters, sizeOfMemCounters)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("GetProcessMemoryInfo failed: %s\n", err)
|
||||
// {{end}}
|
||||
return dump, err
|
||||
}
|
||||
|
||||
heapSize := procMemCounters.WorkingSetSize + IncrementSize
|
||||
|
||||
dumpBuffer, err := syscalls.HeapAlloc(heapHandle, 0x00000008, uintptr(heapSize))
|
||||
if err != nil {
|
||||
return dump, err
|
||||
}
|
||||
stdOutHandle := f.Fd()
|
||||
err = syscalls.MiniDumpWriteDump(proc, pid, stdOutHandle, 3, 0, 0, 0)
|
||||
if err == nil {
|
||||
data, err := ioutil.ReadFile(f.Name())
|
||||
dump.data = data
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("ReadFile failed:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
os.Remove(f.Name())
|
||||
} else {
|
||||
|
||||
outData := outDump{
|
||||
outPtr: dumpBuffer,
|
||||
}
|
||||
|
||||
callbackInfo := MiniDumpCallbackInformation{
|
||||
CallbackRoutine: windows.NewCallback(minidumpCallback),
|
||||
CallbackParam: uintptr(unsafe.Pointer(&outData)),
|
||||
}
|
||||
|
||||
err = syscalls.MiniDumpWriteDump(
|
||||
proc,
|
||||
pid,
|
||||
0,
|
||||
MiniDumpWithFullMemory,
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&callbackInfo)),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
//{{if .Config.Debug}}
|
||||
log.Println("Minidump syscall failed:", err)
|
||||
//{{end}}
|
||||
return dump, err
|
||||
}
|
||||
outBuff := make([]byte, bytesRead)
|
||||
outBuffAddr := uintptr(unsafe.Pointer(&outBuff[0]))
|
||||
syscalls.RtlCopyMemory(outBuffAddr, outData.outPtr, bytesRead)
|
||||
err = syscalls.HeapFree(heapHandle, 0, outData.outPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("HeapFree failed: \n", err)
|
||||
// {{end}}
|
||||
return dump, err
|
||||
}
|
||||
dump.data = outBuff
|
||||
return dump, nil
|
||||
}
|
||||
|
||||
type MiniDumpIOCallback struct {
|
||||
Handle uintptr
|
||||
Offset uint64
|
||||
Buffer uintptr
|
||||
BufferBytes uint32
|
||||
}
|
||||
|
||||
type MiniDumpCallbackInput struct {
|
||||
ProcessId uint32
|
||||
ProcessHandle uintptr
|
||||
CallbackType uint32
|
||||
Io MiniDumpIOCallback
|
||||
}
|
||||
|
||||
type MiniDumpCallbackOutput struct {
|
||||
Status int32
|
||||
}
|
||||
|
||||
type MiniDumpCallbackInformation struct {
|
||||
CallbackRoutine uintptr
|
||||
CallbackParam uintptr
|
||||
}
|
||||
|
||||
func getCallbackInput(callbackInputPtr uintptr) (*MiniDumpCallbackInput, error) {
|
||||
callbackInput := MiniDumpCallbackInput{}
|
||||
ioCallback := MiniDumpIOCallback{}
|
||||
bufferSize := unsafe.Sizeof(callbackInput)
|
||||
data := make([]byte, bufferSize)
|
||||
dataPtr := uintptr(unsafe.Pointer(&data[0]))
|
||||
syscalls.RtlCopyMemory(dataPtr, callbackInputPtr, uint32(bufferSize))
|
||||
buffReader := bytes.NewReader(data)
|
||||
err := binary.Read(buffReader, binary.LittleEndian, &callbackInput.ProcessId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var procHandle uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &procHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
callbackInput.ProcessHandle = uintptr(procHandle)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &callbackInput.CallbackType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ioHandle uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioHandle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ioCallback.Handle = uintptr(ioHandle)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioCallback.Offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ioBuffer uint64
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioBuffer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ioCallback.Buffer = uintptr(ioBuffer)
|
||||
err = binary.Read(buffReader, binary.LittleEndian, &ioCallback.BufferBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
callbackInput.Io = ioCallback
|
||||
return &callbackInput, nil
|
||||
}
|
||||
|
||||
func minidumpCallback(callbackParam uintptr, callbackInputPtr uintptr, callbackOutput *MiniDumpCallbackOutput) uintptr {
|
||||
callbackInput, err := getCallbackInput(callbackInputPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("getCallbackInput failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
switch callbackInput.CallbackType {
|
||||
case IoStartCallback:
|
||||
callbackOutput.Status = S_FALSE
|
||||
case IoWriteAllCallback:
|
||||
callbackOutput.Status = S_OK
|
||||
outData := (*outDump)(unsafe.Pointer(callbackParam))
|
||||
procHeap, err := syscalls.GetProcessHeap()
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback GetProcessHeap failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
currentBuffSize, err := syscalls.HeapSize(procHeap, 0, outData.outPtr)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback HeapSize failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
bytesAndOffset := callbackInput.Io.Offset + uint64(callbackInput.Io.BufferBytes)
|
||||
if bytesAndOffset >= uint64(currentBuffSize) {
|
||||
increasedSize := IncrementSize
|
||||
if bytesAndOffset <= uint64(currentBuffSize*2) {
|
||||
increasedSize = int(currentBuffSize) * 2
|
||||
} else {
|
||||
increasedSize += int(bytesAndOffset)
|
||||
}
|
||||
outData.outPtr, err = syscalls.HeapReAlloc(procHeap, 0, outData.outPtr, uintptr(increasedSize))
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("minidumpCallback HeapReAlloc failed: %s\n", err.Error())
|
||||
// {{end}}
|
||||
return FALSE
|
||||
}
|
||||
}
|
||||
destination := outData.outPtr + uintptr(callbackInput.Io.Offset)
|
||||
syscalls.RtlCopyMemory(destination, callbackInput.Io.Buffer, callbackInput.Io.BufferBytes)
|
||||
bytesRead += callbackInput.Io.BufferBytes
|
||||
case IoFinishCallback:
|
||||
callbackOutput.Status = S_OK
|
||||
default:
|
||||
return TRUE
|
||||
}
|
||||
return TRUE
|
||||
}
|
||||
@@ -5,6 +5,8 @@ package syscalls
|
||||
//sys InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) = kernel32.InitializeProcThreadAttributeList
|
||||
//sys GetProcessHeap() (procHeap windows.Handle, err error) = kernel32.GetProcessHeap
|
||||
//sys HeapAlloc(hHeap windows.Handle, dwFlags uint32, dwBytes uintptr) (lpMem uintptr, err error) = kernel32.HeapAlloc
|
||||
//sys HeapReAlloc(hHeap windows.Handle, dwFlags uint32, lpMem uintptr, dwBytes uintptr) (lpRes uintptr, err error) = kernel32.HeapReAlloc
|
||||
//sys HeapSize(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (res uint32, err error) = kernel32.HeapSize
|
||||
//sys UpdateProcThreadAttribute(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwFlags uint32, attribute uintptr, lpValue *uintptr, cbSize uintptr, lpPreviousValue uintptr, lpReturnSize *uintptr) (err error) = kernel32.UpdateProcThreadAttribute
|
||||
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *windows.SecurityAttributes, threadSecurity *windows.SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfoEx, outProcInfo *windows.ProcessInformation) (err error) = kernel32.CreateProcessW
|
||||
//sys VirtualAllocEx(hProcess windows.Handle, lpAddress uintptr, dwSize uintptr, flAllocationType uint32, flProtect uint32) (addr uintptr, err error) = kernel32.VirtualAllocEx
|
||||
@@ -35,5 +37,9 @@ package syscalls
|
||||
//sys SelectObject(hdc windows.Handle, h windows.Handle) (HGDIOBJ windows.Handle, err error) = Gdi32.SelectObject
|
||||
//sys BitBlt(hdc windows.Handle, x uint32, y uint32, cx uint32, cy uint32, hdcSrc windows.Handle, x1 uint32, y1 uint32, rop int32) (BOOL int, err error) = Gdi32.BitBlt
|
||||
//sys GetDIBits(hdc windows.Handle, hbm windows.Handle, start uint32, cLines uint32, lpvBits uintptr, lpbmi uintptr, usage int) (ret int, err error) = Gdi32.GetDIBits
|
||||
//sys PssCaptureSnapshot(processHandle windows.Handle, captureFlags uint32, threadContextFlags uint32, snapshotHandle *windows.Handle) (err error) = kernel32.PssCaptureSnapshot
|
||||
|
||||
//sys RtlCopyMemory(dest uintptr, src uintptr, dwSize uint32) = ntdll.RtlCopyMemory
|
||||
//sys GetProcessMemoryInfo(process windows.Handle, ppsmemCounters *ProcessMemoryCounters, cb uint32) (err error) = psapi.GetProcessMemoryInfo
|
||||
//sys LookupPrivilegeNameW(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
|
||||
//sys LookupPrivilegeDisplayNameW(systemName string, privilegeName *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||
@@ -5,6 +5,40 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
PSS_CAPTURE_NONE = iota
|
||||
PSS_CAPTURE_VA_CLONE
|
||||
PSS_CAPTURE_RESERVED_00000002
|
||||
PSS_CAPTURE_HANDLES
|
||||
PSS_CAPTURE_HANDLE_NAME_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_BASIC_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_TYPE_SPECIFIC_INFORMATION
|
||||
PSS_CAPTURE_HANDLE_TRACE
|
||||
PSS_CAPTURE_THREADS
|
||||
PSS_CAPTURE_THREAD_CONTEXT
|
||||
PSS_CAPTURE_THREAD_CONTEXT_EXTENDED
|
||||
PSS_CAPTURE_RESERVED_00000400
|
||||
PSS_CAPTURE_VA_SPACE
|
||||
PSS_CAPTURE_VA_SPACE_SECTION_INFORMATION
|
||||
PSS_CAPTURE_IPT_TRACE
|
||||
PSS_CAPTURE_RESERVED_00004000
|
||||
PSS_CREATE_BREAKAWAY_OPTIONAL
|
||||
PSS_CREATE_BREAKAWAY
|
||||
PSS_CREATE_FORCE_BREAKAWAY
|
||||
PSS_CREATE_USE_VM_ALLOCATIONS
|
||||
PSS_CREATE_MEASURE_PERFORMANCE
|
||||
PSS_CREATE_RELEASE_SECTION
|
||||
|
||||
CONTEXT_i386 = 0x10000
|
||||
CONTEXT_i486 = 0x10000 // same as i386
|
||||
CONTEXT_CONTROL = CONTEXT_i386 | 0x01 // SS:SP, CS:IP, FLAGS, BP
|
||||
CONTEXT_INTEGER = CONTEXT_i386 | 0x02 // AX, BX, CX, DX, SI, DI
|
||||
CONTEXT_SEGMENTS = CONTEXT_i386 | 0x0 // DS, ES, FS, GS
|
||||
CONTEXT_FLOATING_POINT = CONTEXT_i386 | 0x08 // 387 state
|
||||
CONTEXT_DEBUG_REGISTERS = CONTEXT_i386 | 0x10 // DB 0-3,6,7
|
||||
CONTEXT_EXTENDED_REGISTERS = CONTEXT_i386 | 0x20 // cpu specific extensions
|
||||
CONTEXT_FULL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS
|
||||
CONTEXT_ALL = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS
|
||||
|
||||
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000
|
||||
LOGON32_LOGON_INTERACTIVE = 2
|
||||
LOGON32_LOGON_NETWORK = 3
|
||||
@@ -84,6 +118,19 @@ type MONITORINFO struct {
|
||||
DwFlags uint32
|
||||
}
|
||||
|
||||
type ProcessMemoryCounters struct {
|
||||
Cb uint32
|
||||
PageFaultCount uint32
|
||||
PeakWorkingSetSize int
|
||||
WorkingSetSize int
|
||||
QuotaPeakPagedPoolUsage int
|
||||
QuotaPagedPoolUsage int
|
||||
QuotaPeakNonPagedPoolUsage int
|
||||
QuotaNonPagedPoolUsage int
|
||||
PagefileUsage int
|
||||
PeakPagefileUsage int
|
||||
}
|
||||
|
||||
const (
|
||||
CCHDEVICENAME = 32
|
||||
CCHFORMNAME = 32
|
||||
|
||||
@@ -44,6 +44,8 @@ var (
|
||||
modUser32 = windows.NewLazySystemDLL("User32.dll")
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||
modntdll = windows.NewLazySystemDLL("ntdll.dll")
|
||||
modpsapi = windows.NewLazySystemDLL("psapi.dll")
|
||||
|
||||
procMiniDumpWriteDump = modDbgHelp.NewProc("MiniDumpWriteDump")
|
||||
procBitBlt = modGdi32.NewProc("BitBlt")
|
||||
@@ -72,12 +74,17 @@ var (
|
||||
procGetProcessHeap = modkernel32.NewProc("GetProcessHeap")
|
||||
procHeapAlloc = modkernel32.NewProc("HeapAlloc")
|
||||
procHeapFree = modkernel32.NewProc("HeapFree")
|
||||
procHeapReAlloc = modkernel32.NewProc("HeapReAlloc")
|
||||
procHeapSize = modkernel32.NewProc("HeapSize")
|
||||
procInitializeProcThreadAttributeList = modkernel32.NewProc("InitializeProcThreadAttributeList")
|
||||
procPssCaptureSnapshot = modkernel32.NewProc("PssCaptureSnapshot")
|
||||
procQueueUserAPC = modkernel32.NewProc("QueueUserAPC")
|
||||
procUpdateProcThreadAttribute = modkernel32.NewProc("UpdateProcThreadAttribute")
|
||||
procVirtualAllocEx = modkernel32.NewProc("VirtualAllocEx")
|
||||
procVirtualProtectEx = modkernel32.NewProc("VirtualProtectEx")
|
||||
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
||||
procRtlCopyMemory = modntdll.NewProc("RtlCopyMemory")
|
||||
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
|
||||
)
|
||||
|
||||
func MiniDumpWriteDump(hProcess windows.Handle, pid uint32, hFile uintptr, dumpType uint32, exceptionParam uintptr, userStreamParam uintptr, callbackParam uintptr) (err error) {
|
||||
@@ -333,6 +340,24 @@ func HeapFree(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func HeapReAlloc(hHeap windows.Handle, dwFlags uint32, lpMem uintptr, dwBytes uintptr) (lpRes uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procHeapReAlloc.Addr(), 4, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem), uintptr(dwBytes), 0, 0)
|
||||
lpRes = uintptr(r0)
|
||||
if lpRes == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HeapSize(hHeap windows.Handle, dwFlags uint32, lpMem uintptr) (res uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procHeapSize.Addr(), 3, uintptr(hHeap), uintptr(dwFlags), uintptr(lpMem))
|
||||
res = uint32(r0)
|
||||
if res == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LIST, dwAttributeCount uint32, dwFlags uint32, lpSize *uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procInitializeProcThreadAttributeList.Addr(), 4, uintptr(unsafe.Pointer(lpAttributeList)), uintptr(dwAttributeCount), uintptr(dwFlags), uintptr(unsafe.Pointer(lpSize)), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -341,6 +366,14 @@ func InitializeProcThreadAttributeList(lpAttributeList *PROC_THREAD_ATTRIBUTE_LI
|
||||
return
|
||||
}
|
||||
|
||||
func PssCaptureSnapshot(processHandle windows.Handle, captureFlags uint32, threadContextFlags uint32, snapshotHandle *windows.Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procPssCaptureSnapshot.Addr(), 4, uintptr(processHandle), uintptr(captureFlags), uintptr(threadContextFlags), uintptr(unsafe.Pointer(snapshotHandle)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func QueueUserAPC(pfnAPC uintptr, hThread windows.Handle, dwData uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procQueueUserAPC.Addr(), 3, uintptr(pfnAPC), uintptr(hThread), uintptr(dwData))
|
||||
if r1 == 0 {
|
||||
@@ -381,3 +414,16 @@ func WriteProcessMemory(hProcess windows.Handle, lpBaseAddress uintptr, lpBuffer
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func RtlCopyMemory(dest uintptr, src uintptr, dwSize uint32) {
|
||||
syscall.Syscall(procRtlCopyMemory.Addr(), 3, uintptr(dest), uintptr(src), uintptr(dwSize))
|
||||
return
|
||||
}
|
||||
|
||||
func GetProcessMemoryInfo(process windows.Handle, ppsmemCounters *ProcessMemoryCounters, cb uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(ppsmemCounters)), uintptr(cb))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
+772
-722
File diff suppressed because it is too large.
Load diff
@@ -120,6 +120,8 @@ message Ls {
|
||||
string Path = 1;
|
||||
bool Exists = 2;
|
||||
repeated FileInfo Files = 3;
|
||||
string timezone = 4;
|
||||
int32 timezoneOffset = 5;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
@@ -128,6 +130,8 @@ message FileInfo {
|
||||
string Name = 1;
|
||||
bool IsDir = 2;
|
||||
int64 Size = 3;
|
||||
int64 ModTime = 4;
|
||||
string Mode = 5;
|
||||
}
|
||||
|
||||
message CdReq {
|
||||
@@ -826,6 +830,7 @@ message WindowsPrivilegeEntry {
|
||||
|
||||
message GetPrivs {
|
||||
repeated WindowsPrivilegeEntry PrivInfo = 1;
|
||||
string ProcessIntegrity = 2;
|
||||
|
||||
commonpb.Response Response = 9;
|
||||
}
|
||||
Reference in new issue
Block a user