mirror of
https://github.com/BishopFox/sliver.git
synced 2026-11-10 01:41:29 -10:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73dbe78806 | ||
|
|
b968dcf969 | ||
|
|
9ffe3842a4 | ||
|
|
9b1ce8afa8 | ||
|
|
4ec3c9b776 |
No files matched your search
@@ -13,9 +13,9 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.2"
|
||||
go-version: "1.20.1"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -63,9 +63,9 @@ jobs:
|
||||
timeout-minutes: 45
|
||||
steps:
|
||||
- name: Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.2"
|
||||
go-version: "^1.20"
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
steps:
|
||||
# Setup go environment
|
||||
- name: Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "^1.20"
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ jobs:
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.2"
|
||||
go-version: "^1.20"
|
||||
|
||||
- name: OS Packages
|
||||
run: |
|
||||
@@ -50,9 +50,9 @@ jobs:
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- name: Go 1.20
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.20.2"
|
||||
go-version: "^1.20"
|
||||
|
||||
- name: Mingw
|
||||
run: brew install mingw-w64
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.20.2
|
||||
FROM golang:1.20.1
|
||||
|
||||
#
|
||||
# IMPORTANT: This Dockerfile is used for testing, I do not recommend deploying
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
GO ?= go
|
||||
ARTIFACT_SUFFIX ?=
|
||||
ENV =
|
||||
TAGS ?= -tags osusergo,netgo,wasm_sqlite
|
||||
TAGS ?= -tags osusergo,netgo,cgosqlite,sqlite_omit_load_extension
|
||||
|
||||
|
||||
#
|
||||
@@ -63,6 +63,17 @@ STATIC_TARGET := linux
|
||||
UNAME_S := $(shell uname -s)
|
||||
UNAME_P := $(shell uname -p)
|
||||
|
||||
# If the target is Windows from Linux/Darwin, check for mingw
|
||||
CROSS_COMPILERS = x86_64-w64-mingw32-gcc x86_64-w64-mingw32-g++
|
||||
ifneq (,$(findstring cgosqlite,$(TAGS)))
|
||||
ENV +=CGO_ENABLED=1
|
||||
ifeq ($(MAKECMDGOALS), windows)
|
||||
K := $(foreach exec,$(CROSS_COMPILERS),\
|
||||
$(if $(shell which $(exec)),some string,$(error "Missing cross-compiler $(exec) in PATH")))
|
||||
ENV += CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
|
||||
endif
|
||||
endif
|
||||
|
||||
# Programs required for generating protobuf/grpc files
|
||||
PB_COMPILERS = protoc protoc-gen-go protoc-gen-go-grpc
|
||||
ifeq ($(MAKECMDGOALS), pb)
|
||||
@@ -97,6 +108,12 @@ ifeq ($(MAKECMDGOALS), linux)
|
||||
-X $(CLIENT_ASSETS_PKG).DefaultArmoryRepoURL=$(ARMORY_REPO_URL)"
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS), linux-arm64)
|
||||
# Redefine TAGS/ENV to use pure go sqlite3
|
||||
TAGS = -tags osusergo,netgo,gosqlite
|
||||
ENV = CGO_ENABLED=0
|
||||
endif
|
||||
|
||||
#
|
||||
# Targets
|
||||
#
|
||||
@@ -127,8 +144,8 @@ linux-arm64: clean .downloaded_assets validate-go-version
|
||||
|
||||
.PHONY: windows
|
||||
windows: clean .downloaded_assets validate-go-version
|
||||
GOOS=windows GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX).exe ./server
|
||||
GOOS=windows GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX).exe ./client
|
||||
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX).exe ./server
|
||||
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX).exe ./client
|
||||
|
||||
.PHONY: pb
|
||||
pb:
|
||||
|
||||
@@ -5,7 +5,7 @@ Sliver is an open source cross-platform adversary emulation/red team framework,
|
||||
|
||||
The server and client support MacOS, Windows, and Linux. Implants are supported on MacOS, Windows, and Linux (and possibly every Golang compiler target but we've not tested them all).
|
||||
|
||||
[](https://github.com/BishopFox/sliver/actions/workflows/autorelease.yml) [](https://goreportcard.com/report/github.com/BishopFox/sliver) [](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://goreportcard.com/report/github.com/BishopFox/sliver) [](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
### Features
|
||||
|
||||
|
||||
@@ -289,17 +289,9 @@ func runAliasCommand(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
// Groupping the two conditions together could crash the client since ctx.Flags.Type panics
|
||||
// if the flag is not registered.
|
||||
if aliasManifest.IsAssembly {
|
||||
inProcess := ctx.Flags.Bool("in-process")
|
||||
runtime := ctx.Flags.String("runtime")
|
||||
amsiBypass := ctx.Flags.Bool("amsi-bypass")
|
||||
etwBypass := ctx.Flags.Bool("etw-bypass")
|
||||
if !inProcess {
|
||||
if !ctx.Flags.Bool("in-process") {
|
||||
msgStr = " Arguments are limited to 256 characters when using the default fork/exec model for .NET assemblies.\nConsider using the --in-process flag to execute .NET assemblies in-process and work around this limitation.\n"
|
||||
}
|
||||
if !inProcess && (runtime != "" || etwBypass || amsiBypass) {
|
||||
con.PrintErrorf("The --runtime, --etw-bypass, and --amsi-bypass flags can only be used with the --in-process flag\n")
|
||||
return
|
||||
}
|
||||
} else if !aliasManifest.IsReflective {
|
||||
msgStr = " Arguments are limited to 256 characters when using the default fork/exec model for non-reflective PE payloads.\n"
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ func fetchPackageSignature(wg *sync.WaitGroup, armoryConfig *assets.ArmoryConfig
|
||||
|
||||
var sig *minisign.Signature
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, _, err = pkgParser(armoryConfig, armoryPkg, true, clientConfig)
|
||||
sig, _, err = pkgParser(armoryPkg, true, clientConfig)
|
||||
} else {
|
||||
sig, _, err = DefaultArmoryPkgParser(armoryConfig, armoryPkg, true, clientConfig)
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func installAliasPackageByName(name string, clientConfig ArmoryHTTPConfig, con *
|
||||
var sig *minisign.Signature
|
||||
var tarGz []byte
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, tarGz, err = pkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
|
||||
} else {
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
}
|
||||
@@ -261,7 +261,7 @@ func installExtensionPackageByName(name string, clientConfig ArmoryHTTPConfig, c
|
||||
var sig *minisign.Signature
|
||||
var tarGz []byte
|
||||
if pkgParser, ok := pkgParsers[repoURL.Hostname()]; ok {
|
||||
sig, tarGz, err = pkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
sig, tarGz, err = pkgParser(&entry.Pkg, false, clientConfig)
|
||||
} else {
|
||||
sig, tarGz, err = DefaultArmoryPkgParser(entry.ArmoryConfig, &entry.Pkg, false, clientConfig)
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
type ArmoryIndexParser func(*assets.ArmoryConfig, ArmoryHTTPConfig) (*ArmoryIndex, error)
|
||||
|
||||
// ArmoryPackageParser - Generic interface to fetch armory package manifests
|
||||
type ArmoryPackageParser func(*assets.ArmoryConfig, *ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error)
|
||||
type ArmoryPackageParser func(*ArmoryPackage, bool, ArmoryHTTPConfig) (*minisign.Signature, []byte, error)
|
||||
|
||||
var (
|
||||
indexParsers = map[string]ArmoryIndexParser{
|
||||
@@ -79,7 +79,28 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
|
||||
client := httpClient(clientConfig)
|
||||
repoURL, err := url.Parse(armoryConfig.RepoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: repoURL,
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
if armoryConfig.Authorization != "" {
|
||||
req.Header.Set("Authorization", armoryConfig.Authorization)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New("api returned non-200 status code")
|
||||
}
|
||||
@@ -104,8 +125,9 @@ func DefaultArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig Ar
|
||||
return nil, errors.New("index has invalid signature")
|
||||
}
|
||||
|
||||
armoryIndex := &ArmoryIndex{
|
||||
ArmoryConfig: armoryConfig,
|
||||
armoryIndex := &ArmoryIndex{ArmoryConfig: armoryConfig}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(armoryIndexData, armoryIndex)
|
||||
if err != nil {
|
||||
@@ -122,7 +144,25 @@ func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *Armory
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
|
||||
client := httpClient(clientConfig)
|
||||
repoURL, err := url.Parse(armoryConfig.RepoURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
req := &http.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: repoURL,
|
||||
Header: map[string][]string{},
|
||||
}
|
||||
if armoryConfig.Authorization != "" {
|
||||
req.Header.Set("Authorization", armoryConfig.Authorization)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -147,10 +187,18 @@ func DefaultArmoryPkgParser(armoryConfig *assets.ArmoryConfig, armoryPkg *Armory
|
||||
if tarGzURL.Scheme != "https" && tarGzURL.Scheme != "http" {
|
||||
return nil, nil, errors.New("invalid url scheme")
|
||||
}
|
||||
tarGz, err = downloadRequest(clientConfig, tarGzURL.String(), armoryConfig)
|
||||
resp, err := client.Get(tarGzURL.String())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
tarGz, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, nil, errors.New("api returned non-200 status code")
|
||||
}
|
||||
}
|
||||
return sig, tarGz, nil
|
||||
}
|
||||
@@ -191,7 +239,13 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, body, err := httpRequest(clientConfig, armoryConfig.RepoURL, armoryConfig, http.Header{})
|
||||
client := httpClient(clientConfig)
|
||||
resp, err := client.Get(armoryConfig.RepoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -199,7 +253,7 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
|
||||
if resp.StatusCode == http.StatusForbidden {
|
||||
return nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
|
||||
}
|
||||
return nil, fmt.Errorf("api returned non-200 status code: %d", resp.StatusCode)
|
||||
return nil, errors.New("api returned non-200 status code")
|
||||
}
|
||||
|
||||
releases := []GithubRelease{}
|
||||
@@ -216,13 +270,23 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
|
||||
var sigData []byte
|
||||
for _, asset := range release.Assets {
|
||||
if asset.Name == armoryIndexFileName {
|
||||
armoryIndexData, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
|
||||
resp, err := client.Get(asset.BrowserDownloadURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
armoryIndexData, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if asset.Name == armoryIndexSigFileName {
|
||||
sigData, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
|
||||
resp, err := client.Get(asset.BrowserDownloadURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
sigData, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -235,9 +299,7 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
|
||||
return nil, errors.New("invalid signature")
|
||||
}
|
||||
|
||||
armoryIndex := &ArmoryIndex{
|
||||
ArmoryConfig: armoryConfig,
|
||||
}
|
||||
armoryIndex := &ArmoryIndex{}
|
||||
err = json.Unmarshal(armoryIndexData, armoryIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -246,14 +308,20 @@ func GithubAPIArmoryIndexParser(armoryConfig *assets.ArmoryConfig, clientConfig
|
||||
}
|
||||
|
||||
// GithubAPIArmoryPackageParser - Retrieve the minisig and tar.gz for an armory package from a GitHub release
|
||||
func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
func GithubAPIArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
var publicKey minisign.PublicKey
|
||||
err := publicKey.UnmarshalText([]byte(armoryPkg.PublicKey))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
resp, body, err := httpRequest(clientConfig, armoryPkg.RepoURL, armoryConfig, http.Header{})
|
||||
client := httpClient(clientConfig)
|
||||
resp, err := client.Get(armoryPkg.RepoURL)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -261,7 +329,7 @@ func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *
|
||||
if resp.StatusCode == http.StatusForbidden {
|
||||
return nil, nil, errors.New("you hit the github api rate limit (60 req/hr), try later")
|
||||
}
|
||||
return nil, nil, fmt.Errorf("api returned non-200 status code: %d", resp.StatusCode)
|
||||
return nil, nil, errors.New("api returned non-200 status code")
|
||||
}
|
||||
|
||||
releases := []GithubRelease{}
|
||||
@@ -275,7 +343,14 @@ func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *
|
||||
var tarGz []byte
|
||||
for _, asset := range release.Assets {
|
||||
if asset.Name == fmt.Sprintf("%s.minisig", armoryPkg.CommandName) {
|
||||
body, err := downloadRequest(clientConfig, asset.URL, armoryConfig)
|
||||
var resp *http.Response
|
||||
resp, err = client.Get(asset.BrowserDownloadURL)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var body []byte
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
@@ -285,7 +360,13 @@ func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *
|
||||
}
|
||||
}
|
||||
if asset.Name == fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName) && !sigOnly {
|
||||
tarGz, err = downloadRequest(clientConfig, asset.URL, armoryConfig)
|
||||
var resp *http.Response
|
||||
resp, err = client.Get(asset.BrowserDownloadURL)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
tarGz, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
@@ -299,27 +380,31 @@ func GithubAPIArmoryPackageParser(armoryConfig *assets.ArmoryConfig, armoryPkg *
|
||||
//
|
||||
|
||||
// GithubArmoryPackageParser - Uses github.com instead of api.github.com to download packages
|
||||
func GithubArmoryPackageParser(_ *assets.ArmoryConfig, armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
func GithubArmoryPackageParser(armoryPkg *ArmoryPackage, sigOnly bool, clientConfig ArmoryHTTPConfig) (*minisign.Signature, []byte, error) {
|
||||
latestTag, err := githubLatestTagParser(armoryPkg, clientConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
client := httpClient(clientConfig)
|
||||
|
||||
sigURL, err := url.Parse(armoryPkg.RepoURL)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
|
||||
}
|
||||
sigURL.Path = path.Join(sigURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.minisig", armoryPkg.CommandName))
|
||||
|
||||
// Setup dummy auth here as the non-api endpoints don't support the Authorization header
|
||||
noAuth := &assets.ArmoryConfig{
|
||||
Authorization: "",
|
||||
}
|
||||
body, err := downloadRequest(clientConfig, sigURL.String(), noAuth)
|
||||
sigResp, err := client.Get(sigURL.String())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
defer sigResp.Body.Close()
|
||||
if sigResp.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("failed to get signature for armory pkg '%s': %s", armoryPkg.RepoURL, sigResp.Status)
|
||||
}
|
||||
var body []byte
|
||||
body, err = ioutil.ReadAll(sigResp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read resp body '%s': %s", armoryPkg.RepoURL, err)
|
||||
}
|
||||
sig, err := parsePkgMinsig(body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse pkg sig '%s': %s", armoryPkg.RepoURL, err)
|
||||
@@ -332,10 +417,18 @@ func GithubArmoryPackageParser(_ *assets.ArmoryConfig, armoryPkg *ArmoryPackage,
|
||||
return nil, nil, fmt.Errorf("failed to parse armory pkg url '%s': %s", armoryPkg.RepoURL, err)
|
||||
}
|
||||
tarGzURL.Path = path.Join(tarGzURL.Path, "releases", "download", latestTag, fmt.Sprintf("%s.tar.gz", armoryPkg.CommandName))
|
||||
tarGz, err = downloadRequest(clientConfig, tarGzURL.String(), noAuth)
|
||||
tarGzResp, err := client.Get(tarGzURL.String())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer tarGzResp.Body.Close()
|
||||
if tarGzResp.StatusCode != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("failed to get tar.gz for armory pkg '%s': %s", armoryPkg.RepoURL, tarGzResp.Status)
|
||||
}
|
||||
tarGz, err = ioutil.ReadAll(tarGzResp.Body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read tar.gz body '%s': %s", armoryPkg.RepoURL, err)
|
||||
}
|
||||
}
|
||||
|
||||
return sig, tarGz, nil
|
||||
@@ -405,40 +498,3 @@ func httpClient(config ArmoryHTTPConfig) *http.Client {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func httpRequest(clientConfig ArmoryHTTPConfig, reqURL string, armoryConfig *assets.ArmoryConfig, extraHeaders http.Header) (*http.Response, []byte, error) {
|
||||
client := httpClient(clientConfig)
|
||||
req, err := http.NewRequest(http.MethodGet, reqURL, http.NoBody)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(extraHeaders) > 0 {
|
||||
for key := range extraHeaders {
|
||||
req.Header.Add(key, strings.Join(extraHeaders[key], ","))
|
||||
}
|
||||
}
|
||||
if armoryConfig.Authorization != "" {
|
||||
req.Header.Set("Authorization", armoryConfig.Authorization)
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
return resp, body, err
|
||||
}
|
||||
|
||||
func downloadRequest(clientConfig ArmoryHTTPConfig, reqURL string, armoryConfig *assets.ArmoryConfig) ([]byte, error) {
|
||||
downloadHdr := http.Header{
|
||||
"Accept": {"application/octet-stream"},
|
||||
}
|
||||
resp, body, err := httpRequest(clientConfig, reqURL, armoryConfig, downloadHdr)
|
||||
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusFound {
|
||||
return nil, fmt.Errorf("Error downloading asset: http %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return body, err
|
||||
}
|
||||
@@ -2143,70 +2143,6 @@ func BindCommands(con *console.SliverConsoleClient) {
|
||||
},
|
||||
})
|
||||
|
||||
con.App.AddCommand(&grumble.Command{
|
||||
Name: consts.ChmodStr,
|
||||
Help: "Change permissions on a file or directory",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ChmodStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("r", "recursive", false, "recursively change permissions on files")
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("path", "path to the file to remove")
|
||||
a.String("mode", "file permissions in octal, e.g. 0644")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
filesystem.ChmodCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
|
||||
con.App.AddCommand(&grumble.Command{
|
||||
Name: consts.ChownStr,
|
||||
Help: "Change owner on a file or directory",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ChownStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Bool("r", "recursive", false, "recursively change permissions on files")
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("path", "path to the file to remove")
|
||||
a.String("uid", "User, e.g. root")
|
||||
a.String("gid", "Group, e.g. root")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
filesystem.ChownCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
|
||||
con.App.AddCommand(&grumble.Command{
|
||||
Name: consts.ChtimesStr,
|
||||
Help: "Change access and modification times on a file (timestomp)",
|
||||
LongHelp: help.GetHelpFor([]string{consts.ChtimesStr}),
|
||||
Flags: func(f *grumble.Flags) {
|
||||
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
|
||||
},
|
||||
Args: func(a *grumble.Args) {
|
||||
a.String("path", "path to the file to remove")
|
||||
a.String("atime", "Last accessed time in DateTime format, i.e. 2006-01-02 15:04:05")
|
||||
a.String("mtime", "Last modified time in DateTime format, i.e. 2006-01-02 15:04:05")
|
||||
},
|
||||
Run: func(ctx *grumble.Context) error {
|
||||
con.Println()
|
||||
filesystem.ChtimesCmd(ctx, con)
|
||||
con.Println()
|
||||
return nil
|
||||
},
|
||||
HelpGroup: consts.SliverHelpGroup,
|
||||
})
|
||||
|
||||
// [ Websites ] ---------------------------------------------
|
||||
|
||||
websitesCmd := &grumble.Command{
|
||||
|
||||
@@ -66,11 +66,6 @@ func ExecuteAssemblyCmd(ctx *grumble.Context, con *console.SliverConsoleClient)
|
||||
etwBypass := ctx.Flags.Bool("etw-bypass")
|
||||
amsiBypass := ctx.Flags.Bool("amsi-bypass")
|
||||
|
||||
if !inProcess && (runtime != "" || etwBypass || amsiBypass) {
|
||||
con.PrintErrorf("The --runtime, --etw-bypass, and --amsi-bypass flags can only be used with the --in-process flag\n")
|
||||
return
|
||||
}
|
||||
|
||||
assemblyArgsStr := strings.Join(assemblyArgs, " ")
|
||||
assemblyArgsStr = strings.TrimSpace(assemblyArgsStr)
|
||||
if len(assemblyArgsStr) > 256 && !inProcess {
|
||||
|
||||
@@ -69,13 +69,10 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
con.PrintErrorf("You must specify a keytab file with the --kerberos-keytab flag\n")
|
||||
return
|
||||
}
|
||||
kerberosKeytab := []byte{}
|
||||
if kerberosKeytabFile != "" {
|
||||
kerberosKeytab, err = os.ReadFile(kerberosKeytabFile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
kerberosKeytab, err := os.ReadFile(kerberosKeytabFile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
if password == "" && len(privKey) == 0 && !ctx.Flags.Bool("skip-loot") {
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package filesystem
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 b0yd
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// ChmodCmd - Change the permissions of a file on the remote file system
|
||||
func ChmodCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
filePath := ctx.Args.String("path")
|
||||
|
||||
if filePath == "" {
|
||||
con.PrintErrorf("Missing parameter: file or directory name\n")
|
||||
return
|
||||
}
|
||||
|
||||
fileMode := ctx.Args.String("mode")
|
||||
|
||||
if fileMode == "" {
|
||||
con.PrintErrorf("Missing parameter: file permissions (mode)\n")
|
||||
return
|
||||
}
|
||||
|
||||
chmod, err := con.Rpc.Chmod(context.Background(), &sliverpb.ChmodReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: filePath,
|
||||
FileMode: fileMode,
|
||||
Recursive: ctx.Flags.Bool("recursive"),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if chmod.Response != nil && chmod.Response.Async {
|
||||
con.AddBeaconCallback(chmod.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, chmod)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintChmod(chmod, con)
|
||||
})
|
||||
con.PrintAsyncResponse(chmod.Response)
|
||||
} else {
|
||||
PrintChmod(chmod, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintChmod - Print the chmod response
|
||||
func PrintChmod(chmod *sliverpb.Chmod, con *console.SliverConsoleClient) {
|
||||
if chmod.Response != nil && chmod.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", chmod.Response.Err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("%s\n", chmod.Path)
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package filesystem
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 b0yd
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// ChownCmd - Change the owner of a file on the remote file system
|
||||
func ChownCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
|
||||
filePath := ctx.Args.String("path")
|
||||
|
||||
if filePath == "" {
|
||||
con.PrintErrorf("Missing parameter: file or directory name\n")
|
||||
return
|
||||
}
|
||||
|
||||
uid := ctx.Args.String("uid")
|
||||
|
||||
if uid == "" {
|
||||
con.PrintErrorf("Missing parameter: user id\n")
|
||||
return
|
||||
}
|
||||
|
||||
gid := ctx.Args.String("gid")
|
||||
|
||||
if gid == "" {
|
||||
con.PrintErrorf("Missing parameter: group id\n")
|
||||
return
|
||||
}
|
||||
|
||||
chown, err := con.Rpc.Chown(context.Background(), &sliverpb.ChownReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: filePath,
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
Recursive: ctx.Flags.Bool("recursive"),
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if chown.Response != nil && chown.Response.Async {
|
||||
con.AddBeaconCallback(chown.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, chown)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintChown(chown, con)
|
||||
})
|
||||
con.PrintAsyncResponse(chown.Response)
|
||||
} else {
|
||||
PrintChown(chown, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintChown - Print the chown response
|
||||
func PrintChown(chown *sliverpb.Chown, con *console.SliverConsoleClient) {
|
||||
if chown.Response != nil && chown.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", chown.Response.Err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("%s\n", chown.Path)
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
package filesystem
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 b0yd
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/bishopfox/sliver/client/console"
|
||||
"github.com/bishopfox/sliver/protobuf/clientpb"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/desertbit/grumble"
|
||||
)
|
||||
|
||||
// ChtimesCmd - Change the access and modified time of a file on the remote file system
|
||||
func ChtimesCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
|
||||
session, beacon := con.ActiveTarget.GetInteractive()
|
||||
if session == nil && beacon == nil {
|
||||
return
|
||||
}
|
||||
// DateTime layout (https://pkg.go.dev/time)
|
||||
layout := "2006-01-02 15:04:05"
|
||||
filePath := ctx.Args.String("path")
|
||||
|
||||
if filePath == "" {
|
||||
con.PrintErrorf("Missing parameter: file or directory name\n")
|
||||
return
|
||||
}
|
||||
|
||||
atime := ctx.Args.String("atime")
|
||||
|
||||
if atime == "" {
|
||||
con.PrintErrorf("Missing parameter: Last accessed time id\n")
|
||||
return
|
||||
}
|
||||
|
||||
t_a, err := time.Parse(layout, atime)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
unixAtime := t_a.Unix()
|
||||
|
||||
mtime := ctx.Args.String("mtime")
|
||||
|
||||
if mtime == "" {
|
||||
con.PrintErrorf("Missing parameter: Last modified time id\n")
|
||||
return
|
||||
}
|
||||
|
||||
t_b, err := time.Parse(layout, mtime)
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
unixMtime := t_b.Unix()
|
||||
|
||||
chtimes, err := con.Rpc.Chtimes(context.Background(), &sliverpb.ChtimesReq{
|
||||
Request: con.ActiveTarget.Request(ctx),
|
||||
Path: filePath,
|
||||
ATime: unixAtime,
|
||||
MTime: unixMtime,
|
||||
})
|
||||
if err != nil {
|
||||
con.PrintErrorf("%s\n", err)
|
||||
return
|
||||
}
|
||||
if chtimes.Response != nil && chtimes.Response.Async {
|
||||
con.AddBeaconCallback(chtimes.Response.TaskID, func(task *clientpb.BeaconTask) {
|
||||
err = proto.Unmarshal(task.Response, chtimes)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode response %s\n", err)
|
||||
return
|
||||
}
|
||||
PrintChtimes(chtimes, con)
|
||||
})
|
||||
con.PrintAsyncResponse(chtimes.Response)
|
||||
} else {
|
||||
PrintChtimes(chtimes, con)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintChtimes - Print the Chtimes response
|
||||
func PrintChtimes(chtimes *sliverpb.Chtimes, con *console.SliverConsoleClient) {
|
||||
if chtimes.Response != nil && chtimes.Response.Err != "" {
|
||||
con.PrintErrorf("%s\n", chtimes.Response.Err)
|
||||
return
|
||||
}
|
||||
con.PrintInfof("%s\n", chtimes.Path)
|
||||
}
|
||||
@@ -149,22 +149,13 @@ func PrintLs(ls *sliverpb.Ls, flags grumble.FlagMap, con *console.SliverConsoleC
|
||||
implantLocation := time.FixedZone(ls.Timezone, int(ls.TimezoneOffset))
|
||||
modTime = modTime.In(implantLocation)
|
||||
|
||||
owner := ""
|
||||
if fileInfo.Uid != "" {
|
||||
owner = fileInfo.Uid
|
||||
}
|
||||
if fileInfo.Gid != "" {
|
||||
owner = owner + ":" + fileInfo.Gid + "\t"
|
||||
}
|
||||
|
||||
if fileInfo.IsDir {
|
||||
fmt.Fprintf(table, "%s\t%s%s\t<dir>\t%s\n", fileInfo.Mode, owner, fileInfo.Name, modTime.Format(time.RubyDate))
|
||||
fmt.Fprintf(table, "%s\t%s\t<dir>\t%s\n", fileInfo.Mode, fileInfo.Name, modTime.Format(time.RubyDate))
|
||||
} else if fileInfo.Link != "" {
|
||||
fmt.Fprintf(table, "%s\t%s%s -> %s\t%s\t%s\n", fileInfo.Mode, owner, fileInfo.Name, fileInfo.Link, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
|
||||
fmt.Fprintf(table, "%s\t%s -> %s\t%s\t%s\n", fileInfo.Mode, fileInfo.Name, fileInfo.Link, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
|
||||
} else {
|
||||
fmt.Fprintf(table, "%s\t%s%s\t%s\t%s\n", fileInfo.Mode, owner, fileInfo.Name, util.ByteCountBinary(fileInfo.Size), modTime.Format(time.RubyDate))
|
||||
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()
|
||||
con.Printf("%s\n", outputBuf.String())
|
||||
|
||||
@@ -488,9 +488,10 @@ func ParseHTTPc2(args string) ([]*clientpb.ImplantC2, error) {
|
||||
return c2s, nil
|
||||
}
|
||||
for index, arg := range strings.Split(args, ",") {
|
||||
arg = strings.ToLower(arg)
|
||||
var uri *url.URL
|
||||
var err error
|
||||
if cmp := strings.ToLower(arg); strings.HasPrefix(cmp, "http://") || strings.HasPrefix(cmp, "https://") {
|
||||
if strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
|
||||
uri, err = url.Parse(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -17,7 +17,7 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol
|
||||
return data, err
|
||||
}
|
||||
|
||||
implantName := buildImplantName(profile.GetConfig().GetFileName())
|
||||
implantName := buildImplantName(profile.GetConfig().GetName())
|
||||
_, ok := builds.GetConfigs()[implantName]
|
||||
if implantName == "" || !ok {
|
||||
// no built implant found for profile, generate a new one
|
||||
@@ -35,7 +35,7 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol
|
||||
return data, err
|
||||
}
|
||||
data = generated.GetFile().GetData()
|
||||
profile.Config.FileName = generated.File.Name
|
||||
profile.Config.Name = buildImplantName(generated.GetFile().GetName())
|
||||
_, err = con.Rpc.SaveImplantProfile(context.Background(), profile)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Error updating implant profile\n")
|
||||
@@ -45,7 +45,7 @@ func GetSliverBinary(profile *clientpb.ImplantProfile, con *console.SliverConsol
|
||||
// Found a build, reuse that one
|
||||
con.PrintInfof("Sliver name for profile: %s\n", implantName)
|
||||
regenerate, err := con.Rpc.Regenerate(context.Background(), &clientpb.RegenerateReq{
|
||||
ImplantName: implantName,
|
||||
ImplantName: profile.GetConfig().GetName(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -424,33 +424,6 @@ func renderTaskResponse(task *clientpb.BeaconTask, con *console.SliverConsoleCli
|
||||
}
|
||||
filesystem.PrintUpload(upload, con)
|
||||
|
||||
case sliverpb.MsgChmodReq:
|
||||
chmod := &sliverpb.Chmod{}
|
||||
err := proto.Unmarshal(task.Response, chmod)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintChmod(chmod, con)
|
||||
|
||||
case sliverpb.MsgChownReq:
|
||||
chown := &sliverpb.Chown{}
|
||||
err := proto.Unmarshal(task.Response, chown)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintChown(chown, con)
|
||||
|
||||
case sliverpb.MsgChtimesReq:
|
||||
chtimes := &sliverpb.Chtimes{}
|
||||
err := proto.Unmarshal(task.Response, chtimes)
|
||||
if err != nil {
|
||||
con.PrintErrorf("Failed to decode task response: %s\n", err)
|
||||
return
|
||||
}
|
||||
filesystem.PrintChtimes(chtimes, con)
|
||||
|
||||
// ---------------------
|
||||
// Network commands
|
||||
// ---------------------
|
||||
|
||||
@@ -187,9 +187,6 @@ const (
|
||||
UploadStr = "upload"
|
||||
IfconfigStr = "ifconfig"
|
||||
NetstatStr = "netstat"
|
||||
ChmodStr = "chmod"
|
||||
ChownStr = "chown"
|
||||
ChtimesStr = "chtimes"
|
||||
|
||||
ProcdumpStr = "procdump"
|
||||
ImpersonateStr = "impersonate"
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"github.com/chromedp/cdproto/cdp"
|
||||
"github.com/chromedp/cdproto/network"
|
||||
"github.com/chromedp/cdproto/page"
|
||||
"github.com/chromedp/cdproto/storage"
|
||||
"github.com/chromedp/cdproto/target"
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
@@ -276,7 +275,7 @@ func DumpCookies(curse *core.CursedProcess, webSocketURL string) ([]*network.Coo
|
||||
dumpCookieTasks := chromedp.Tasks{
|
||||
// read network values
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
cookies, err = storage.GetCookies().Do(ctx)
|
||||
cookies, err = network.GetCookies().Do(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ set -e
|
||||
|
||||
# Creates the static go asset archives
|
||||
|
||||
GO_VER="1.20.2"
|
||||
GARBLE_VER="1.20.3"
|
||||
GO_VER="1.20.1"
|
||||
GARBLE_VER="1.20.2"
|
||||
SGN_VER="0.0.3"
|
||||
|
||||
GO_ARCH_1="amd64"
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ echo "----------------------------------------------------------------"
|
||||
echo "WARNING: Running unit tests on slow systems can take a LONG time"
|
||||
echo " Recommended to only run on 16+ CPU cores and 32Gb+ RAM"
|
||||
echo "----------------------------------------------------------------"
|
||||
TAGS=osusergo,netgo,wasm_sqlite
|
||||
TAGS=osusergo,netgo,cgosqlite,sqlite_omit_load_extension
|
||||
|
||||
## Client
|
||||
|
||||
|
||||
@@ -12,49 +12,48 @@ require (
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
|
||||
github.com/Ne0nd0g/go-clr v1.0.3
|
||||
github.com/alecthomas/chroma v0.10.0
|
||||
github.com/cheggaaa/pb/v3 v3.1.2
|
||||
github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9
|
||||
github.com/chromedp/chromedp v0.9.1
|
||||
github.com/cheggaaa/pb/v3 v3.1.0
|
||||
github.com/chromedp/cdproto v0.0.0-20230109101555-6b041c6303cc
|
||||
github.com/chromedp/chromedp v0.8.7
|
||||
github.com/desertbit/columnize v2.1.0+incompatible
|
||||
github.com/desertbit/go-shlex v0.1.1
|
||||
github.com/desertbit/grumble v1.1.1
|
||||
github.com/desertbit/readline v1.5.1
|
||||
github.com/fatih/color v1.15.0
|
||||
github.com/fatih/color v1.14.1
|
||||
github.com/gofrs/uuid v4.4.0+incompatible
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.6
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
github.com/lesnuages/snitch v0.6.0
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/miekg/dns v1.1.52
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
|
||||
github.com/ncruces/go-sqlite3 v0.5.3
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/things-go/go-socks5 v0.0.3
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
|
||||
github.com/xlab/treeprint v1.1.0
|
||||
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
|
||||
golang.org/x/crypto v0.7.0
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/term v0.6.0
|
||||
golang.org/x/text v0.8.0
|
||||
golang.org/x/crypto v0.6.0
|
||||
golang.org/x/net v0.7.0
|
||||
golang.org/x/sys v0.5.0
|
||||
golang.org/x/term v0.5.0
|
||||
golang.org/x/text v0.7.0
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68
|
||||
google.golang.org/grpc v1.54.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84
|
||||
google.golang.org/protobuf v1.28.1
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.8
|
||||
gorm.io/driver/mysql v1.4.7
|
||||
gorm.io/driver/postgres v1.5.0
|
||||
gorm.io/driver/postgres v1.4.8
|
||||
gorm.io/driver/sqlite v1.4.4
|
||||
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11
|
||||
gorm.io/gorm v1.24.5
|
||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
|
||||
modernc.org/sqlite v1.21.0
|
||||
modernc.org/sqlite v1.20.4
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -62,7 +61,7 @@ require (
|
||||
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab // indirect
|
||||
github.com/VividCortex/ewma v1.2.0 // indirect
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
@@ -97,18 +96,16 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/ncruces/julianday v0.1.5 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/tetratelabs/wazero v1.0.0 // indirect
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
|
||||
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
|
||||
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
|
||||
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
|
||||
@@ -118,9 +115,9 @@ require (
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.22.3 // indirect
|
||||
modernc.org/libc v1.22.2 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y=
|
||||
cloud.google.com/go/compute v1.15.1 h1:7UGq3QknM33pw5xATlpzeoomNxsacIVvTqTTvbfajmE=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
|
||||
@@ -30,26 +29,27 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab h1:96tkQLYmgypA3W42fvC3UX3EoOP3hQZuT7d98lnnwyc=
|
||||
github.com/VirusTotal/vt-go v0.0.0-20210528074736-45bbe34cc8ab/go.mod h1:u1+HeRyl/gQs67eDgVEWNE7+x+zCyXhdtNVrRJR5YPE=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
|
||||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/akamensky/argparse v1.2.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/akamensky/argparse v1.3.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cheggaaa/pb/v3 v3.1.2 h1:FIxT3ZjOj9XJl0U4o2XbEhjFfZl7jCVCDOGq1ZAB7wQ=
|
||||
github.com/cheggaaa/pb/v3 v3.1.2/go.mod h1:SNjnd0yKcW+kw0brSusraeDd5Bf1zBfxAzTL2ss3yQ4=
|
||||
github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9 h1:wMSvdj3BswqfQOXp2R1bJOAE7xIQLt2dlMQDMf836VY=
|
||||
github.com/chromedp/cdproto v0.0.0-20230220211738-2b1ec77315c9/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.9.1 h1:CC7cC5p1BeLiiS2gfNNPwp3OaUxtRMBjfiw3E3k6dFA=
|
||||
github.com/chromedp/chromedp v0.9.1/go.mod h1:DUgZWRvYoEfgi66CgZ/9Yv+psgi+Sksy5DTScENWjaQ=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/pb/v3 v3.1.0 h1:3uouEsl32RL7gTiQsuaXD4Bzbfl5tGztXGUvXbs4O04=
|
||||
github.com/cheggaaa/pb/v3 v3.1.0/go.mod h1:YjrevcBqadFDaGQKRdmZxTY42pXEqda48Ea3lt0K/BE=
|
||||
github.com/chromedp/cdproto v0.0.0-20230109101555-6b041c6303cc h1:pgBIUnhrsNh0Xi+8qUdHIP/nljIVz3laeRv23eqr45M=
|
||||
github.com/chromedp/cdproto v0.0.0-20230109101555-6b041c6303cc/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.8.7 h1:dYOYc5ynTBzwSLOi+1IfgHwPr8r2BqV48l/RC+3OuJ0=
|
||||
github.com/chromedp/chromedp v0.8.7/go.mod h1:iL+ywnwk3eG3EVXV1ackXBMNzdEh3Ye/KHvQkq1KRKU=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
@@ -58,6 +58,12 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWs
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
@@ -83,17 +89,21 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@@ -112,24 +122,38 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/uuid v1.1.2/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.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -154,8 +178,8 @@ github.com/jackc/pgx/v5 v5.3.0/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHo
|
||||
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
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/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
@@ -171,6 +195,7 @@ github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
@@ -182,7 +207,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
|
||||
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
|
||||
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
|
||||
@@ -204,6 +228,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
@@ -214,21 +239,16 @@ github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWC
|
||||
github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c=
|
||||
github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||
github.com/moloch--/grumble v1.1.6 h1:FjPkuGOIwGL8nGkEH0EegnQgsl6Rn0R0fhBW/kcA0s8=
|
||||
github.com/moloch--/grumble v1.1.6/go.mod h1:r7j3ShNy5EmOsegRD2DzTutIaGiLiA3M5yBTXXeLwcs=
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 h1:m3yCfV8Vqp4MF1B+gPPjbjINdufl0UXqyYplE0aGhx8=
|
||||
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945/go.mod h1:1grVt4HaTofvhFUZYtofeRbGXfczNwCie9MYoM4lP/o=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/ncruces/go-sqlite3 v0.5.3 h1:n7kYgRp5CVZepOiZql/pgPG3IelkUIF95AE70EiM8JE=
|
||||
github.com/ncruces/go-sqlite3 v0.5.3/go.mod h1:bC0Wm1XQMcTz7BZzINEYFHLvfzxh+NbZftPo40xkfuc=
|
||||
github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk=
|
||||
github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
@@ -237,11 +257,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -261,6 +282,7 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -268,23 +290,22 @@ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tetratelabs/wazero v1.0.0 h1:sCE9+mjFex95Ki6hdqwvhyF25x5WslADjDKIFU5BXzI=
|
||||
github.com/tetratelabs/wazero v1.0.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2 h1:CoMVaYyKFsVj6TjU6APqAhAvC07hTI6IQen8PHzHYY0=
|
||||
github.com/thedevsaddam/gojsonq/v2 v2.5.2/go.mod h1:bv6Xa7kWy82uT0LnXPE2SzGqTj33TAEeR560MdJkiXs=
|
||||
github.com/things-go/go-socks5 v0.0.3 h1:QtlIhkwDuLNCwW3wnt2uTjn1mQzpyjnwct2xdPuqroI=
|
||||
github.com/things-go/go-socks5 v0.0.3/go.mod h1:f8Zx+n8kfzyT90hXM767cP6sysAud93+t9rV90IgMcg=
|
||||
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43 h1:+sN63SJGqchSsVyNoeW4GyA0Y+g0LvKOHcaeqs1Rf6M=
|
||||
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43/go.mod h1:dhnDTBbIg31cbJdROP4/Zz6Iw7JPEpiMvOl2LdHSSjE=
|
||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e h1:6SWomM8ezwUwnN3lqKxE4r7bYVwpY9514DQkwBV9IPI=
|
||||
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e/go.mod h1:r1bHcNa22x8rrg/Kj/cDF5bX6UtZrHiQgRFvj3Mnpl8=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@@ -295,40 +316,47 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -346,6 +374,7 @@ golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -354,10 +383,12 @@ golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -365,27 +396,25 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -393,13 +422,14 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -418,19 +448,34 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
|
||||
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f h1:YORWxaStkWBnWgELOHTmDrqNlFXuVGEbhwbB5iK94bQ=
|
||||
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84 h1:hZAzgyItS2MPyqvdC8wQZI99ZLGP9Vwijyfr0dmYWc4=
|
||||
google.golang.org/grpc v1.42.0-dev.0.20211020220737-f00baa6c3c84/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.8 h1:5UtTowJZTz1j7NxVzDGKTz6Lm9IWm8DDF6b7a2wq9VY=
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3eoHtnX5UgUo=
|
||||
@@ -450,21 +495,21 @@ gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuv
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU=
|
||||
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.4.7 h1:rY46lkCspzGHn7+IYsNpSfEv9tA+SU4SkkB+GFX125Y=
|
||||
gorm.io/driver/mysql v1.4.7/go.mod h1:SxzItlnT1cb6e1e4ZRpgJN2VYtcqJgqnHxWr4wsP8oc=
|
||||
gorm.io/driver/postgres v1.5.0 h1:u2FXTy14l45qc3UeCJ7QaAXZmZfDDv0YrthvmRq1l0U=
|
||||
gorm.io/driver/postgres v1.5.0/go.mod h1:FUZXzO+5Uqg5zzwzv4KK49R8lvGIyscBOqYrtI1Ce9A=
|
||||
gorm.io/driver/postgres v1.4.8 h1:NDWizaclb7Q2aupT0jkwK8jx1HVCNzt+PQ8v/VnxviA=
|
||||
gorm.io/driver/postgres v1.4.8/go.mod h1:O9MruWGNLUBUWVYfWuBClpf3HeGjOoybY0SNmCs3wsw=
|
||||
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
|
||||
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
|
||||
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11 h1:9qNbmu21nNThCNnF5i2R3kw2aL27U8ZwbzccNjOmW0g=
|
||||
gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
|
||||
gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gorm.io/gorm v1.24.5 h1:g6OPREKqqlWq4kh/3MCQbZKImeB9e6Xgc4zD+JgNZGE=
|
||||
gorm.io/gorm v1.24.5/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
|
||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 h1:cv/zaNV0nr1mJzaeo4S5mHIm5va1W0/9J3/5prlsuRM=
|
||||
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -477,19 +522,19 @@ modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/libc v1.22.3 h1:D/g6O5ftAfavceqlLOFwaZuA5KYafKwmr30A6iSqoyY=
|
||||
modernc.org/libc v1.22.3/go.mod h1:MQrloYP209xa2zHome2a8HLiLm6k0UT8CoHpV74tOFw=
|
||||
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
|
||||
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.21.0 h1:4aP4MdUf15i3R3M2mx6Q90WHKz3nZLoz96zlB6tNdow=
|
||||
modernc.org/sqlite v1.21.0/go.mod h1:XwQ0wZPIh1iKb5mkvCJ3szzbhk+tykC8ZWqTRTgYRwI=
|
||||
modernc.org/sqlite v1.20.4 h1:J8+m2trkN+KKoE7jglyHYYYiaq5xmz2HoHJIiBlRzbE=
|
||||
modernc.org/sqlite v1.20.4/go.mod h1:zKcGyrICaxNTMEHSr1HQ2GUraP0j+845GYw37+EyT6A=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
|
||||
modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34=
|
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
|
||||
+2
-5
@@ -3,8 +3,8 @@ module github.com/bishopfox/sliver
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313
|
||||
github.com/Ne0nd0g/go-clr v1.0.3
|
||||
github.com/Ne0nd0g/go-clr v1.0.2
|
||||
github.com/ebitengine/purego v0.2.0-alpha.1.0.20230221135432-0c858ac9f9ff
|
||||
github.com/gofrs/uuid v4.0.0+incompatible
|
||||
github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f
|
||||
github.com/lesnuages/go-winio v0.4.19
|
||||
@@ -23,11 +23,8 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2 // indirect
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 // indirect
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 // indirect
|
||||
|
||||
+4
-11
@@ -1,22 +1,16 @@
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2 h1:8kQNJC9AxAaNs0JkXnWUfbNeDnIO1QLYYWjYqC6JEE4=
|
||||
github.com/Binject/debug v0.0.0-20210225042342-c9b8b45728d2/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313 h1:hX9boCRvCxIpsiV4q9ts+WOYNnjHiji2FOR5BsDzxiY=
|
||||
github.com/Binject/universal v0.0.0-20210304094126-daefaa886313/go.mod h1:J3XDRlam5pPYca3i6EqgQ35GCCEoyxafpCbLkta0ozc=
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc h1:7D+Bh06CRPCJO3gr2F7h1sriovOZ8BMhca2Rg85c2nk=
|
||||
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Ne0nd0g/go-clr v1.0.3 h1:xt92wwuqY23ZSC7RuHD3mKu3K22Bk5NNbxI803vojK4=
|
||||
github.com/Ne0nd0g/go-clr v1.0.3/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0 h1:JjwxKkxzcBk4k8147g0eBQRCIy0UN1Be8AAv6RaIj4Q=
|
||||
github.com/awgh/cppgo v0.0.0-20210224085512-3d24bca8edc0/go.mod h1:IbERvuyb387Hppp8hX0SQTFt/mkej8+OhuS8L0nC2CI=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4 h1:cIAK2NNf2yafdgpFRNJrgZMwvy61BEVpGoHc2n4/yWs=
|
||||
github.com/awgh/rawreader v0.0.0-20200626064944-56820a9c6da4/go.mod h1:SalMPBCab3yuID8nIhLfzwoBV+lBRyaC7NhuN8qL8xE=
|
||||
github.com/Ne0nd0g/go-clr v1.0.2 h1:jVD7iJyXaS3KhPiKetUnUAuLxgDlNSvYmPfMFK8E3VY=
|
||||
github.com/Ne0nd0g/go-clr v1.0.2/go.mod h1:TKYSQ/5xT25EvBUttAlUrzpR8yHuI0qTRK495I5xG/I=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/purego v0.2.0-alpha.1.0.20230221135432-0c858ac9f9ff h1:lf1Eoi7P7gXh+L7ngFxSr3szq91PWRgRiLm9cei0M0M=
|
||||
github.com/ebitengine/purego v0.2.0-alpha.1.0.20230221135432-0c858ac9f9ff/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u70Gtw93ZOu2UuPeeeTBDntF7FoY=
|
||||
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||
@@ -82,7 +76,6 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build darwin
|
||||
|
||||
package extension
|
||||
|
||||
/*
|
||||
@@ -19,34 +21,26 @@ package extension
|
||||
*/
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"runtime"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
"github.com/Binject/universal"
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
type DarwinExtension struct {
|
||||
id string
|
||||
data []byte
|
||||
module *universal.Library
|
||||
module uintptr
|
||||
arch string
|
||||
serverStore bool
|
||||
init string
|
||||
onFinish func([]byte)
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type extensionArguments struct {
|
||||
inDataSize uintptr
|
||||
inDataBuff uintptr
|
||||
outDataSize uintptr
|
||||
outDataBuff uintptr
|
||||
}
|
||||
|
||||
func NewDarwinExtension(data []byte, id string, arch string, init string) *DarwinExtension {
|
||||
return &DarwinExtension{
|
||||
id: id,
|
||||
@@ -65,65 +59,58 @@ func (d *DarwinExtension) GetArch() string {
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) Load() error {
|
||||
var err error
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
loader, err := universal.NewLoader()
|
||||
|
||||
extTmpFile, err := createTempFile(d.data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.module, err = loader.LoadLibrary(d.id, &d.data)
|
||||
if err != nil {
|
||||
return err
|
||||
defer cleanupTempFile(extTmpFile)
|
||||
d.module = purego.Dlopen(extTmpFile, purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||
if err := purego.Dlerror(); err != "" {
|
||||
return errors.New(err)
|
||||
}
|
||||
|
||||
if d.init != "" {
|
||||
if _, errInit := d.module.Call(d.init); errInit != nil {
|
||||
return errInit
|
||||
}
|
||||
var initFunc func()
|
||||
purego.RegisterLibFunc(&initFunc, d.module, d.init)
|
||||
initFunc()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) Call(export string, arguments []byte, onFinish func([]byte)) error {
|
||||
// We currently have 2 issues with Darwin extensions:
|
||||
// - cppgo (used by universal) fucks up when calling a function with more than 1 argument
|
||||
// - we don't have Go callback support for the loaded extension,
|
||||
// so we have to wait for the call to finish to get the results
|
||||
// To circumvent these issues, we pass the extensionArguments structure
|
||||
// as the only argument to the call, so we can pass args in and extract
|
||||
// the result at the same time.
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
extArgs := extensionArguments{}
|
||||
if len(arguments) > 0 {
|
||||
extArgs.inDataBuff = uintptr(unsafe.Pointer(&arguments[0]))
|
||||
extArgs.inDataSize = uintptr(uint64(len(arguments)))
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Calling %s, arg size: %d\n", export, extArgs.inDataSize)
|
||||
// {{end}}
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
_, err := d.module.Call(export, uintptr(unsafe.Pointer(&extArgs)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("%s done!\n", export)
|
||||
// {{end}}
|
||||
outData := new(bytes.Buffer)
|
||||
outDataSize := int(extArgs.outDataSize)
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("Out data size: %d\n", outDataSize)
|
||||
// {{end}}
|
||||
for i := 0; i < outDataSize; i++ {
|
||||
b := (*byte)(unsafe.Pointer(uintptr(i) + extArgs.outDataBuff))
|
||||
outData.WriteByte(*b)
|
||||
}
|
||||
// We currently don't have a way to trigger a callback
|
||||
// in the loaded code for Darwin.
|
||||
if outData.Len() > 0 {
|
||||
onFinish(outData.Bytes())
|
||||
}
|
||||
d.onFinish = onFinish
|
||||
outCallback := purego.NewCallback(d.extensionCallback)
|
||||
var exportFunc func([]byte, uint64, uintptr) uint32
|
||||
purego.RegisterLibFunc(&exportFunc, d.module, export)
|
||||
exportFunc(arguments, uint64(len(arguments)), outCallback)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DarwinExtension) extensionCallback(data uintptr, length uintptr) {
|
||||
outDataSize := int(length)
|
||||
outBytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), outDataSize)
|
||||
d.onFinish(outBytes)
|
||||
}
|
||||
|
||||
func createTempFile(data []byte) (string, error) {
|
||||
tmpFile, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
_, err = tmpFile.Write(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return tmpFile.Name(), nil
|
||||
}
|
||||
|
||||
func cleanupTempFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
@@ -37,11 +37,12 @@ const (
|
||||
)
|
||||
|
||||
type WindowsExtension struct {
|
||||
id string
|
||||
data []byte
|
||||
module *memmod.Module
|
||||
arch string
|
||||
init string
|
||||
id string
|
||||
data []byte
|
||||
module *memmod.Module
|
||||
arch string
|
||||
init string
|
||||
onFinish func([]byte)
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -100,7 +101,8 @@ func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([
|
||||
if w.module == nil {
|
||||
return errors.New("{{if .Config.Debug}} module not loaded {{end}}")
|
||||
}
|
||||
callback := syscall.NewCallback(newWindowsExtensionCallback(onFinish))
|
||||
w.onFinish = onFinish
|
||||
callback := syscall.NewCallback(w.extensionCallback)
|
||||
exportPtr, err := w.module.ProcAddressByName(export)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -125,15 +127,13 @@ func (w *WindowsExtension) Call(export string, arguments []byte, onFinish func([
|
||||
return nil
|
||||
}
|
||||
|
||||
func newWindowsExtensionCallback(onFinish func([]byte)) func(data uintptr, dataLen uintptr) uintptr {
|
||||
// extensionCallback takes a buffer (char *) and its size (int) as parameters
|
||||
// so we can pass data back to the Go process from the loaded DLL
|
||||
return func(data uintptr, dataLen uintptr) uintptr {
|
||||
outDataSize := int(dataLen)
|
||||
outBytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), outDataSize)
|
||||
if dataLen > 0 {
|
||||
onFinish(outBytes)
|
||||
}
|
||||
return Success
|
||||
// extensionCallback takes a buffer (char *) and its size (int) as parameters
|
||||
// so we can pass data back to the Go process from the loaded DLL
|
||||
func (w *WindowsExtension) extensionCallback(data uintptr, dataLen uintptr) uintptr {
|
||||
outDataSize := int(dataLen)
|
||||
outBytes := unsafe.Slice((*byte)(unsafe.Pointer(data)), outDataSize)
|
||||
if dataLen > 0 {
|
||||
w.onFinish(outBytes)
|
||||
}
|
||||
return Success
|
||||
}
|
||||
@@ -208,10 +208,6 @@ func dirListHandler(data []byte, resp RPCResponse) {
|
||||
linkPath = ""
|
||||
}
|
||||
}
|
||||
|
||||
sliverFileInfo.Uid = getUid(fileInfo)
|
||||
sliverFileInfo.Gid = getGid(fileInfo)
|
||||
|
||||
sliverFileInfo.Name = dirEntry.Name()
|
||||
sliverFileInfo.IsDir = dirEntry.IsDir()
|
||||
sliverFileInfo.Link = linkPath
|
||||
@@ -616,11 +612,6 @@ func executeHandler(data []byte, resp RPCResponse) {
|
||||
Err: fmt.Sprintf("%s", err),
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
}()
|
||||
|
||||
if cmd.Process != nil {
|
||||
execResp.Pid = uint32(cmd.Process.Pid)
|
||||
}
|
||||
@@ -961,41 +952,3 @@ func expandPath(exePath string) (string, error) {
|
||||
}
|
||||
return exePath, nil
|
||||
}
|
||||
|
||||
func chtimesHandler(data []byte, resp RPCResponse) {
|
||||
chtimesReq := &sliverpb.ChtimesReq{}
|
||||
err := proto.Unmarshal(data, chtimesReq)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("error decoding message: %v", err)
|
||||
// {{end}}
|
||||
return
|
||||
}
|
||||
|
||||
chtimes := &sliverpb.Chtimes{}
|
||||
target, _ := filepath.Abs(chtimesReq.Path)
|
||||
chtimes.Path = target
|
||||
// Make sure file exists
|
||||
_, err = os.Stat(target)
|
||||
|
||||
chtimes.Response = &commonpb.Response{}
|
||||
if err == nil {
|
||||
|
||||
unixAtime := int64(chtimesReq.ATime)
|
||||
atime := time.Unix(unixAtime, 0)
|
||||
|
||||
unixMtime := int64(chtimesReq.MTime)
|
||||
mtime := time.Unix(unixMtime, 0)
|
||||
|
||||
err = os.Chtimes(target, atime, mtime)
|
||||
if err != nil {
|
||||
chtimes.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
} else {
|
||||
chtimes.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
data, err = proto.Marshal(chtimes)
|
||||
resp(data, err)
|
||||
}
|
||||
@@ -19,10 +19,6 @@ package handlers
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"syscall"
|
||||
"strconv"
|
||||
"github.com/bishopfox/sliver/implant/sliver/extension"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
@@ -47,7 +43,6 @@ var (
|
||||
pb.MsgEnvReq: getEnvHandler,
|
||||
pb.MsgSetEnvReq: setEnvHandler,
|
||||
pb.MsgUnsetEnvReq: unsetEnvHandler,
|
||||
pb.MsgChtimesReq: chtimesHandler,
|
||||
|
||||
pb.MsgScreenshotReq: screenshotHandler,
|
||||
pb.MsgNetstatReq: netstatHandler,
|
||||
@@ -145,23 +140,3 @@ func listExtensionsHandler(data []byte, resp RPCResponse) {
|
||||
data, err = proto.Marshal(lstResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func getUid(fileInfo os.FileInfo) (string) {
|
||||
uid := int32(fileInfo.Sys().(*syscall.Stat_t).Uid)
|
||||
uid_str := strconv.FormatUint(uint64(uid), 10)
|
||||
usr, err := user.LookupId(uid_str)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Name
|
||||
}
|
||||
|
||||
func getGid(fileInfo os.FileInfo) (string) {
|
||||
gid := int32(fileInfo.Sys().(*syscall.Stat_t).Gid)
|
||||
gid_str := strconv.FormatUint(uint64(gid), 10)
|
||||
grp, err := user.LookupGroupId(gid_str)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return grp.Name
|
||||
}
|
||||
@@ -27,7 +27,6 @@ package handlers
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
)
|
||||
|
||||
@@ -47,7 +46,6 @@ var (
|
||||
sliverpb.MsgEnvReq: getEnvHandler,
|
||||
sliverpb.MsgUnsetEnvReq: unsetEnvHandler,
|
||||
sliverpb.MsgReconfigureReq: reconfigureHandler,
|
||||
sliverpb.MsgChtimesReq: chtimesHandler,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -60,13 +58,3 @@ func GetSystemHandlers() map[uint32]RPCHandler {
|
||||
func GetSystemPivotHandlers() map[uint32]PivotHandler {
|
||||
return map[uint32]PivotHandler{}
|
||||
}
|
||||
|
||||
// Stub
|
||||
func getUid(fileInfo os.FileInfo) (string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Stub
|
||||
func getGid(fileInfo os.FileInfo) (string) {
|
||||
return ""
|
||||
}
|
||||
@@ -19,19 +19,7 @@ package handlers
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"syscall"
|
||||
"strconv"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"github.com/bishopfox/sliver/protobuf/sliverpb"
|
||||
"github.com/bishopfox/sliver/protobuf/commonpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
"log"
|
||||
// {{end}}
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -72,11 +60,6 @@ var (
|
||||
sliverpb.MsgWGStopSocksReq: wgStopSocksHandler,
|
||||
sliverpb.MsgWGListSocksReq: wgListSocksServersHandler,
|
||||
// {{end}}
|
||||
|
||||
// Linux Only
|
||||
sliverpb.MsgChmodReq: chmodHandler,
|
||||
sliverpb.MsgChownReq: chownHandler,
|
||||
sliverpb.MsgChtimesReq: chtimesHandler,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -84,185 +67,3 @@ var (
|
||||
func GetSystemHandlers() map[uint32]RPCHandler {
|
||||
return linuxHandlers
|
||||
}
|
||||
|
||||
func getUid(fileInfo os.FileInfo) (string) {
|
||||
uid := int32(fileInfo.Sys().(*syscall.Stat_t).Uid)
|
||||
uid_str := strconv.FormatUint(uint64(uid), 10)
|
||||
usr, err := user.LookupId(uid_str)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return usr.Name
|
||||
}
|
||||
|
||||
func getGid(fileInfo os.FileInfo) (string) {
|
||||
gid := int32(fileInfo.Sys().(*syscall.Stat_t).Gid)
|
||||
gid_str := strconv.FormatUint(uint64(gid), 10)
|
||||
grp, err := user.LookupGroupId(gid_str)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return grp.Name
|
||||
}
|
||||
|
||||
func chmodHandler(data []byte, resp RPCResponse) {
|
||||
chmodReq := &sliverpb.ChmodReq{}
|
||||
err := proto.Unmarshal(data, chmodReq)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("error decoding message: %v", err)
|
||||
// {{end}}
|
||||
return
|
||||
}
|
||||
|
||||
chmod := &sliverpb.Chmod{}
|
||||
target, _ := filepath.Abs(chmodReq.Path)
|
||||
chmod.Path = target
|
||||
// Make sure file exists
|
||||
_, err = os.Stat(target)
|
||||
|
||||
chmod.Response = &commonpb.Response{}
|
||||
if err == nil {
|
||||
// Convert string to octal number
|
||||
octal, err := strconv.ParseInt(chmodReq.FileMode, 8, 32)
|
||||
if err == nil {
|
||||
|
||||
setuid := octal & 04000
|
||||
setgid := octal & 02000
|
||||
setstcky := octal & 01000
|
||||
|
||||
// Cast the octal number to fs.FileMode
|
||||
fileMode := os.FileMode(octal)
|
||||
|
||||
// Found this was necessary because the constructor above doesn't set special permissions
|
||||
if setuid > 0 {
|
||||
fileMode = fileMode | os.ModeSetuid
|
||||
}
|
||||
if setgid > 0 {
|
||||
fileMode = fileMode | os.ModeSetgid
|
||||
}
|
||||
if setstcky > 0 {
|
||||
fileMode = fileMode | os.ModeSticky
|
||||
}
|
||||
|
||||
if chmodReq.Recursive {
|
||||
|
||||
err := filepath.WalkDir(target, func(file string, d fs.DirEntry, err error) error {
|
||||
if err == nil {
|
||||
err = os.Chmod(file, fileMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
chmod.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
} else {
|
||||
err = os.Chmod(target, fileMode)
|
||||
if err != nil {
|
||||
chmod.Response.Err = err.Error()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chmod.Response.Err = err.Error()
|
||||
}
|
||||
} else {
|
||||
chmod.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
data, err = proto.Marshal(chmod)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
func chownHandler(data []byte, resp RPCResponse) {
|
||||
|
||||
// variable definitions so goto won't break
|
||||
var uid_str string
|
||||
var gid_str string
|
||||
var gid uint64
|
||||
var uid uint64
|
||||
var err error
|
||||
var usr *user.User
|
||||
var grp *user.Group
|
||||
|
||||
chownReq := &sliverpb.ChownReq{}
|
||||
err = proto.Unmarshal(data, chownReq)
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("error decoding message: %v", err)
|
||||
// {{end}}
|
||||
return
|
||||
}
|
||||
|
||||
chown := &sliverpb.Chown{}
|
||||
target, _ := filepath.Abs(chownReq.Path)
|
||||
chown.Path = target
|
||||
_, err = os.Stat(target)
|
||||
|
||||
chown.Response = &commonpb.Response{}
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
goto finished
|
||||
}
|
||||
|
||||
uid_str = chownReq.Uid
|
||||
usr, err = user.Lookup(uid_str)
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
goto finished
|
||||
}
|
||||
|
||||
uid, err = strconv.ParseUint(usr.Uid, 10, 32)
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
goto finished
|
||||
}
|
||||
|
||||
gid_str = chownReq.Gid
|
||||
grp, err = user.LookupGroup(gid_str)
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
goto finished
|
||||
}
|
||||
|
||||
gid, err = strconv.ParseUint(grp.Gid, 10, 32)
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
goto finished
|
||||
}
|
||||
|
||||
// Check if the recursive flag is set and the path is a directory
|
||||
if chownReq.Recursive {
|
||||
|
||||
err := filepath.WalkDir(target, func(file string, d fs.DirEntry, err error) error {
|
||||
if err == nil {
|
||||
err = os.Chown(file, int(uid), int(gid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
err = os.Chown(target, int(uid), int(gid))
|
||||
if err != nil {
|
||||
chown.Response.Err = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
finished:
|
||||
data, err = proto.Marshal(chown)
|
||||
resp(data, err)
|
||||
}
|
||||
@@ -99,7 +99,6 @@ var (
|
||||
sliverpb.MsgExecuteReq: executeHandler,
|
||||
sliverpb.MsgReconfigureReq: reconfigureHandler,
|
||||
sliverpb.MsgSSHCommandReq: runSSHCommandHandler,
|
||||
sliverpb.MsgChtimesReq: chtimesHandler,
|
||||
|
||||
// Extensions
|
||||
sliverpb.MsgRegisterExtensionReq: registerExtensionHandler,
|
||||
@@ -747,13 +746,3 @@ func listExtensionsHandler(data []byte, resp RPCResponse) {
|
||||
data, err = proto.Marshal(lstResp)
|
||||
resp(data, err)
|
||||
}
|
||||
|
||||
// Stub since Windows doesn't support UID
|
||||
func getUid(fileInfo os.FileInfo) (string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Stub since Windows doesn't support GID
|
||||
func getGid(fileInfo os.FileInfo) (string) {
|
||||
return ""
|
||||
}
|
||||
+40
-70
@@ -394,50 +394,13 @@ func beaconMain(beacon *transports.Beacon, nextCheckin time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var tasksExtensionRegister []*sliverpb.Envelope
|
||||
var tasksOther []*sliverpb.Envelope
|
||||
|
||||
for _, task := range tasks.Tasks {
|
||||
switch task.Type {
|
||||
case sliverpb.MsgRegisterExtensionReq:
|
||||
tasksExtensionRegister = append(tasksExtensionRegister, task)
|
||||
default:
|
||||
tasksOther = append(tasksOther, task)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure extensions are registered before they are called
|
||||
var results []*sliverpb.Envelope
|
||||
for _, r := range beaconHandleTasklist(tasksExtensionRegister) {
|
||||
results = append(results, r)
|
||||
}
|
||||
for _, r := range beaconHandleTasklist(tasksOther) {
|
||||
results = append(results, r)
|
||||
}
|
||||
|
||||
err = beacon.Send(wrapEnvelope(sliverpb.MsgBeaconTasks, &sliverpb.BeaconTasks{
|
||||
ID: InstanceID,
|
||||
Tasks: results,
|
||||
}))
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] error sending results %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] all results sent to server, cleanup ...")
|
||||
// {{end}}
|
||||
return nil
|
||||
}
|
||||
|
||||
func beaconHandleTasklist(tasks []*sliverpb.Envelope) []*sliverpb.Envelope {
|
||||
results := []*sliverpb.Envelope{}
|
||||
resultsMutex := &sync.Mutex{}
|
||||
wg := &sync.WaitGroup{}
|
||||
sysHandlers := handlers.GetSystemHandlers()
|
||||
specHandlers := handlers.GetSpecialHandlers()
|
||||
|
||||
for _, task := range tasks {
|
||||
for _, task := range tasks.Tasks {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] execute task %d", task.Type)
|
||||
// {{end}}
|
||||
@@ -446,41 +409,37 @@ func beaconHandleTasklist(tasks []*sliverpb.Envelope) []*sliverpb.Envelope {
|
||||
data := task.Data
|
||||
taskID := task.ID
|
||||
// {{if eq .Config.GOOS "windows" }}
|
||||
go func() {
|
||||
go handlers.WrapperHandler(handler, data, func(data []byte, err error) {
|
||||
resultsMutex.Lock()
|
||||
defer resultsMutex.Unlock()
|
||||
defer wg.Done()
|
||||
handlers.WrapperHandler(handler, data, func(data []byte, err error) {
|
||||
resultsMutex.Lock()
|
||||
defer resultsMutex.Unlock()
|
||||
// {{if .Config.Debug}}
|
||||
if err != nil {
|
||||
log.Printf("[beacon] handler function returned an error: %s", err)
|
||||
}
|
||||
log.Printf("[beacon] task completed (id: %d)", taskID)
|
||||
// {{end}}
|
||||
results = append(results, &sliverpb.Envelope{
|
||||
ID: taskID,
|
||||
Data: data,
|
||||
})
|
||||
// {{if .Config.Debug}}
|
||||
if err != nil {
|
||||
log.Printf("[beacon] handler function returned an error: %s", err)
|
||||
}
|
||||
log.Printf("[beacon] task completed (id: %d)", taskID)
|
||||
// {{end}}
|
||||
results = append(results, &sliverpb.Envelope{
|
||||
ID: taskID,
|
||||
Data: data,
|
||||
})
|
||||
}()
|
||||
})
|
||||
// {{else}}
|
||||
go func() {
|
||||
go handler(data, func(data []byte, err error) {
|
||||
resultsMutex.Lock()
|
||||
defer resultsMutex.Unlock()
|
||||
defer wg.Done()
|
||||
handler(data, func(data []byte, err error) {
|
||||
resultsMutex.Lock()
|
||||
defer resultsMutex.Unlock()
|
||||
// {{if .Config.Debug}}
|
||||
if err != nil {
|
||||
log.Printf("[beacon] handler function returned an error: %s", err)
|
||||
}
|
||||
log.Printf("[beacon] task completed (id: %d)", taskID)
|
||||
// {{end}}
|
||||
results = append(results, &sliverpb.Envelope{
|
||||
ID: taskID,
|
||||
Data: data,
|
||||
})
|
||||
// {{if .Config.Debug}}
|
||||
if err != nil {
|
||||
log.Printf("[beacon] handler function returned an error: %s", err)
|
||||
}
|
||||
log.Printf("[beacon] task completed (id: %d)", taskID)
|
||||
// {{end}}
|
||||
results = append(results, &sliverpb.Envelope{
|
||||
ID: taskID,
|
||||
Data: data,
|
||||
})
|
||||
}()
|
||||
})
|
||||
// {{end}}
|
||||
} else if task.Type == sliverpb.MsgOpenSession {
|
||||
go openSessionHandler(task.Data)
|
||||
@@ -502,7 +461,6 @@ func beaconHandleTasklist(tasks []*sliverpb.Envelope) []*sliverpb.Envelope {
|
||||
resultsMutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] waiting for task(s) to complete ...")
|
||||
// {{end}}
|
||||
@@ -511,7 +469,19 @@ func beaconHandleTasklist(tasks []*sliverpb.Envelope) []*sliverpb.Envelope {
|
||||
log.Printf("[beacon] all tasks completed, sending results to server")
|
||||
// {{end}}
|
||||
|
||||
return results
|
||||
err = beacon.Send(wrapEnvelope(sliverpb.MsgBeaconTasks, &sliverpb.BeaconTasks{
|
||||
ID: InstanceID,
|
||||
Tasks: results,
|
||||
}))
|
||||
if err != nil {
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] error sending results %s", err)
|
||||
// {{end}}
|
||||
}
|
||||
// {{if .Config.Debug}}
|
||||
log.Printf("[beacon] all results sent to server, cleanup ...")
|
||||
// {{end}}
|
||||
return nil
|
||||
}
|
||||
|
||||
func openSessionHandler(data []byte) {
|
||||
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of Google Inc. 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
|
||||
OWNER 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.
|
||||
-3000
File diff suppressed because it is too large.
Load diff
-32
@@ -1,32 +0,0 @@
|
||||
package elf
|
||||
|
||||
/*
|
||||
Any symbol in the dynamic symbol table (in .dynsym) for which .st_shndx == SHN_UNDEF
|
||||
(references undefined section) is an import, and every other symbol is defined and exported.
|
||||
*/
|
||||
|
||||
// Export - describes a single export entry
|
||||
type Export struct {
|
||||
Name string
|
||||
VirtualAddress uint64
|
||||
}
|
||||
|
||||
// Exports - gets exports
|
||||
func (f *File) Exports() ([]Export, error) {
|
||||
|
||||
var exports []Export
|
||||
symbols, err := f.DynamicSymbols()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range symbols {
|
||||
if s.Section != SHN_UNDEF {
|
||||
exports = append(exports, Export{
|
||||
Name: s.Name,
|
||||
VirtualAddress: s.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return exports, nil
|
||||
}
|
||||
-964
@@ -1,964 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package elf implements access to ELF object files.
|
||||
package elf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// seekStart, seekCurrent, seekEnd are copies of
|
||||
// io.SeekStart, io.SeekCurrent, and io.SeekEnd.
|
||||
// We can't use the ones from package io because
|
||||
// we want this code to build with Go 1.4 during
|
||||
// cmd/dist bootstrap.
|
||||
const (
|
||||
seekStart int = 0
|
||||
seekCurrent int = 1
|
||||
seekEnd int = 2
|
||||
)
|
||||
|
||||
// TODO: error reporting detail
|
||||
|
||||
/*
|
||||
* Internal ELF representation
|
||||
*/
|
||||
|
||||
// A FileHeader represents an ELF file header.
|
||||
type FileHeader struct {
|
||||
Class Class
|
||||
Data Data
|
||||
Version Version
|
||||
OSABI OSABI
|
||||
ABIVersion uint8
|
||||
ByteOrder binary.ByteOrder
|
||||
Type Type
|
||||
Machine Machine
|
||||
Entry uint64
|
||||
SHTOffset int64
|
||||
ShStrIndex int
|
||||
}
|
||||
|
||||
// A File represents an open ELF file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
Sections []*Section
|
||||
Progs []*Prog
|
||||
closer io.Closer
|
||||
gnuNeed []verneed
|
||||
gnuVersym []byte
|
||||
Insertion []byte
|
||||
InsertionEOF []byte
|
||||
|
||||
DynTags []DynTagValue
|
||||
}
|
||||
|
||||
// A SectionHeader represents a single ELF section header.
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
Type SectionType
|
||||
Flags SectionFlag
|
||||
Addr uint64
|
||||
Offset uint64
|
||||
Size uint64
|
||||
Link uint32
|
||||
Info uint32
|
||||
Addralign uint64
|
||||
Entsize uint64
|
||||
|
||||
Shnum int // Section Header Number
|
||||
Shname uint32 // Section Header Name (index)
|
||||
|
||||
// FileSize is the size of this section in the file in bytes.
|
||||
// If a section is compressed, FileSize is the size of the
|
||||
// compressed data, while Size (above) is the size of the
|
||||
// uncompressed data.
|
||||
FileSize uint64
|
||||
}
|
||||
|
||||
// A Section represents a single section in an ELF file.
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
//
|
||||
// ReaderAt may be nil if the section is not easily available
|
||||
// in a random-access form. For example, a compressed section
|
||||
// may have a nil ReaderAt.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
|
||||
compressionType CompressionType
|
||||
compressionOffset int64
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the ELF section.
|
||||
// Even if the section is stored compressed in the ELF file,
|
||||
// Data returns uncompressed data.
|
||||
func (s *Section) Data() ([]byte, error) {
|
||||
dat := make([]byte, s.Size)
|
||||
n, err := io.ReadFull(s.Open(), dat)
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// stringTable reads and returns the string table given by the
|
||||
// specified link value.
|
||||
func (f *File) stringTable(link uint32) ([]byte, error) {
|
||||
if link <= 0 || link >= uint32(len(f.Sections)) {
|
||||
return nil, errors.New("section has invalid string table link")
|
||||
}
|
||||
return f.Sections[link].Data()
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the ELF section.
|
||||
// Even if the section is stored compressed in the ELF file,
|
||||
// the ReadSeeker reads uncompressed data.
|
||||
func (s *Section) Open() io.ReadSeeker {
|
||||
if s.Flags&SHF_COMPRESSED == 0 {
|
||||
return io.NewSectionReader(s.sr, 0, 1<<63-1)
|
||||
}
|
||||
if s.compressionType == COMPRESS_ZLIB {
|
||||
return &readSeekerFromReader{
|
||||
reset: func() (io.Reader, error) {
|
||||
fr := io.NewSectionReader(s.sr, s.compressionOffset, int64(s.FileSize)-s.compressionOffset)
|
||||
return zlib.NewReader(fr)
|
||||
},
|
||||
size: int64(s.Size),
|
||||
}
|
||||
}
|
||||
err := &FormatError{int64(s.Offset), "unknown compression type", s.compressionType}
|
||||
return errorReader{err}
|
||||
}
|
||||
|
||||
// A ProgHeader represents a single ELF program header.
|
||||
type ProgHeader struct {
|
||||
Type ProgType
|
||||
Flags ProgFlag
|
||||
Off uint64
|
||||
Vaddr uint64
|
||||
Paddr uint64
|
||||
Filesz uint64
|
||||
Memsz uint64
|
||||
Align uint64
|
||||
}
|
||||
|
||||
// A Prog represents a single ELF program header in an ELF binary.
|
||||
type Prog struct {
|
||||
ProgHeader
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the ELF program body.
|
||||
func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-1) }
|
||||
|
||||
// A Symbol represents an entry in an ELF symbol table section.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
NameIndex uint32
|
||||
Info, Other byte
|
||||
Section SectionIndex
|
||||
SectIndex uint16
|
||||
Value, Size uint64
|
||||
}
|
||||
|
||||
// ToSym64 - Convert to a Sym64
|
||||
func (s Symbol) ToSym64() (retval Sym64) {
|
||||
|
||||
retval.Name = s.NameIndex
|
||||
retval.Info = s.Info
|
||||
retval.Other = s.Other
|
||||
retval.Shndx = s.SectIndex
|
||||
retval.Value = s.Value
|
||||
retval.Size = s.Size
|
||||
return
|
||||
}
|
||||
|
||||
// ToSym32 - Convert to a Sym32
|
||||
func (s Symbol) ToSym32() (retval Sym32) {
|
||||
|
||||
retval.Name = s.NameIndex
|
||||
retval.Info = s.Info
|
||||
retval.Other = s.Other
|
||||
retval.Shndx = s.SectIndex
|
||||
retval.Value = uint32(s.Value)
|
||||
retval.Size = uint32(s.Size)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
* ELF reader
|
||||
*/
|
||||
|
||||
type FormatError struct {
|
||||
off int64
|
||||
msg string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func (e *FormatError) Error() string {
|
||||
msg := e.msg
|
||||
if e.val != nil {
|
||||
msg += fmt.Sprintf(" '%v' ", e.val)
|
||||
}
|
||||
msg += fmt.Sprintf("in record at byte %#x", e.off)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as an ELF binary.
|
||||
func Open(name string) (*File, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() error {
|
||||
var err error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// SectionByType returns the first section in f with the
|
||||
// given type, or nil if there is no such section.
|
||||
func (f *File) SectionByType(typ SectionType) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Type == typ {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SectionByName returns the first section in f with the
|
||||
// given name, or nil if there is no such section.
|
||||
func (f *File) SectionByName(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewFile creates a new File for accessing an ELF binary in an underlying reader.
|
||||
// The ELF binary is expected to start at position 0 in the ReaderAt.
|
||||
func NewFile(r io.ReaderAt) (*File, error) {
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
// Read and decode ELF identifier
|
||||
var ident [16]uint8
|
||||
if _, err := r.ReadAt(ident[0:], 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ident[0] != '\x7f' || ident[1] != 'E' || ident[2] != 'L' || ident[3] != 'F' {
|
||||
return nil, &FormatError{0, "bad magic number", ident[0:4]}
|
||||
}
|
||||
|
||||
f := new(File)
|
||||
f.Class = Class(ident[EI_CLASS])
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
case ELFCLASS64:
|
||||
// ok
|
||||
default:
|
||||
return nil, &FormatError{0, "unknown ELF class", f.Class}
|
||||
}
|
||||
|
||||
f.Data = Data(ident[EI_DATA])
|
||||
switch f.Data {
|
||||
case ELFDATA2LSB:
|
||||
f.ByteOrder = binary.LittleEndian
|
||||
case ELFDATA2MSB:
|
||||
f.ByteOrder = binary.BigEndian
|
||||
default:
|
||||
return nil, &FormatError{0, "unknown ELF data encoding", f.Data}
|
||||
}
|
||||
|
||||
f.Version = Version(ident[EI_VERSION])
|
||||
if f.Version != EV_CURRENT {
|
||||
return nil, &FormatError{0, "unknown ELF version", f.Version}
|
||||
}
|
||||
|
||||
f.OSABI = OSABI(ident[EI_OSABI])
|
||||
f.ABIVersion = ident[EI_ABIVERSION]
|
||||
|
||||
// Read ELF file header
|
||||
var phoff int64
|
||||
var phentsize, phnum int
|
||||
var shentsize, shnum int
|
||||
f.ShStrIndex = -1
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
hdr := new(Header32)
|
||||
sr.Seek(0, seekStart)
|
||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Type = Type(hdr.Type)
|
||||
f.Machine = Machine(hdr.Machine)
|
||||
f.Entry = uint64(hdr.Entry)
|
||||
if v := Version(hdr.Version); v != f.Version {
|
||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||
}
|
||||
phoff = int64(hdr.Phoff)
|
||||
phentsize = int(hdr.Phentsize)
|
||||
phnum = int(hdr.Phnum)
|
||||
f.SHTOffset = int64(hdr.Shoff)
|
||||
shentsize = int(hdr.Shentsize)
|
||||
shnum = int(hdr.Shnum)
|
||||
f.ShStrIndex = int(hdr.Shstrndx)
|
||||
case ELFCLASS64:
|
||||
hdr := new(Header64)
|
||||
sr.Seek(0, seekStart)
|
||||
if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Type = Type(hdr.Type)
|
||||
f.Machine = Machine(hdr.Machine)
|
||||
f.Entry = hdr.Entry
|
||||
if v := Version(hdr.Version); v != f.Version {
|
||||
return nil, &FormatError{0, "mismatched ELF version", v}
|
||||
}
|
||||
phoff = int64(hdr.Phoff)
|
||||
phentsize = int(hdr.Phentsize)
|
||||
phnum = int(hdr.Phnum)
|
||||
f.SHTOffset = int64(hdr.Shoff)
|
||||
shentsize = int(hdr.Shentsize)
|
||||
shnum = int(hdr.Shnum)
|
||||
f.ShStrIndex = int(hdr.Shstrndx)
|
||||
}
|
||||
|
||||
if shnum > 0 && f.SHTOffset > 0 && (f.ShStrIndex < 0 || f.ShStrIndex >= shnum) {
|
||||
return nil, &FormatError{0, "invalid ELF shstrndx", f.ShStrIndex}
|
||||
}
|
||||
|
||||
// Read program headers
|
||||
f.Progs = make([]*Prog, phnum)
|
||||
for i := 0; i < phnum; i++ {
|
||||
off := phoff + int64(i)*int64(phentsize)
|
||||
sr.Seek(off, seekStart)
|
||||
p := new(Prog)
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
ph := new(Prog32)
|
||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.ProgHeader = ProgHeader{
|
||||
Type: ProgType(ph.Type),
|
||||
Flags: ProgFlag(ph.Flags),
|
||||
Off: uint64(ph.Off),
|
||||
Vaddr: uint64(ph.Vaddr),
|
||||
Paddr: uint64(ph.Paddr),
|
||||
Filesz: uint64(ph.Filesz),
|
||||
Memsz: uint64(ph.Memsz),
|
||||
Align: uint64(ph.Align),
|
||||
}
|
||||
case ELFCLASS64:
|
||||
ph := new(Prog64)
|
||||
if err := binary.Read(sr, f.ByteOrder, ph); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.ProgHeader = ProgHeader{
|
||||
Type: ProgType(ph.Type),
|
||||
Flags: ProgFlag(ph.Flags),
|
||||
Off: ph.Off,
|
||||
Vaddr: ph.Vaddr,
|
||||
Paddr: ph.Paddr,
|
||||
Filesz: ph.Filesz,
|
||||
Memsz: ph.Memsz,
|
||||
Align: ph.Align,
|
||||
}
|
||||
}
|
||||
p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
|
||||
p.ReaderAt = p.sr
|
||||
f.Progs[i] = p
|
||||
}
|
||||
|
||||
// Read section headers
|
||||
f.Sections = make([]*Section, shnum)
|
||||
names := make([]uint32, shnum)
|
||||
for i := 0; i < shnum; i++ {
|
||||
off := f.SHTOffset + int64(i)*int64(shentsize)
|
||||
sr.Seek(off, seekStart)
|
||||
s := new(Section)
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
sh := new(Section32)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names[i] = sh.Name
|
||||
s.SectionHeader = SectionHeader{
|
||||
Type: SectionType(sh.Type),
|
||||
Flags: SectionFlag(sh.Flags),
|
||||
Addr: uint64(sh.Addr),
|
||||
Offset: uint64(sh.Off),
|
||||
FileSize: uint64(sh.Size),
|
||||
Link: sh.Link,
|
||||
Info: sh.Info,
|
||||
Addralign: uint64(sh.Addralign),
|
||||
Entsize: uint64(sh.Entsize),
|
||||
Shnum: i,
|
||||
Shname: sh.Name,
|
||||
}
|
||||
|
||||
case ELFCLASS64:
|
||||
sh := new(Section64)
|
||||
if err := binary.Read(sr, f.ByteOrder, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names[i] = sh.Name
|
||||
s.SectionHeader = SectionHeader{
|
||||
Type: SectionType(sh.Type),
|
||||
Flags: SectionFlag(sh.Flags),
|
||||
Offset: sh.Off,
|
||||
FileSize: sh.Size,
|
||||
Addr: sh.Addr,
|
||||
Link: sh.Link,
|
||||
Info: sh.Info,
|
||||
Addralign: sh.Addralign,
|
||||
Entsize: sh.Entsize,
|
||||
Shnum: i,
|
||||
Shname: sh.Name,
|
||||
}
|
||||
}
|
||||
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
|
||||
|
||||
if s.Flags&SHF_COMPRESSED == 0 {
|
||||
s.ReaderAt = s.sr
|
||||
s.Size = s.FileSize
|
||||
} else {
|
||||
// Read the compression header.
|
||||
switch f.Class {
|
||||
case ELFCLASS32:
|
||||
ch := new(Chdr32)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = uint64(ch.Size)
|
||||
s.Addralign = uint64(ch.Addralign)
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
case ELFCLASS64:
|
||||
ch := new(Chdr64)
|
||||
if err := binary.Read(s.sr, f.ByteOrder, ch); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.compressionType = CompressionType(ch.Type)
|
||||
s.Size = ch.Size
|
||||
s.Addralign = ch.Addralign
|
||||
s.compressionOffset = int64(binary.Size(ch))
|
||||
}
|
||||
}
|
||||
|
||||
f.Sections[i] = s
|
||||
}
|
||||
|
||||
if err := f.parseDynTags(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(f.Sections) == 0 {
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Load section header string table.
|
||||
shstrtab, err := f.Sections[f.ShStrIndex].Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, s := range f.Sections {
|
||||
var ok bool
|
||||
s.Name, ok = getString(shstrtab, int(names[i]))
|
||||
if !ok {
|
||||
return nil, &FormatError{f.SHTOffset + int64(i*shentsize), "bad section name index", names[i]}
|
||||
}
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// getSymbols returns a slice of Symbols from parsing the symbol table
|
||||
// with the given type, along with the associated string table.
|
||||
func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, error) {
|
||||
switch f.Class {
|
||||
case ELFCLASS64:
|
||||
return f.getSymbols64(typ)
|
||||
|
||||
case ELFCLASS32:
|
||||
return f.getSymbols32(typ)
|
||||
}
|
||||
|
||||
return nil, nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
// ErrNoSymbols is returned by File.Symbols and File.DynamicSymbols
|
||||
// if there is no such section in the File.
|
||||
var ErrNoSymbols = errors.New("no symbol section")
|
||||
|
||||
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
|
||||
symtabSection := f.SectionByType(typ)
|
||||
if symtabSection == nil {
|
||||
return nil, nil, ErrNoSymbols
|
||||
}
|
||||
|
||||
data, err := symtabSection.Data()
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("cannot load symbol section")
|
||||
}
|
||||
symtab := bytes.NewReader(data)
|
||||
if symtab.Len()%Sym32Size != 0 {
|
||||
return nil, nil, errors.New("length of symbol section is not a multiple of SymSize")
|
||||
}
|
||||
|
||||
strdata, err := f.stringTable(symtabSection.Link)
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("cannot load string table section")
|
||||
}
|
||||
|
||||
// The first entry is all zeros.
|
||||
var skip [Sym32Size]byte
|
||||
symtab.Read(skip[:])
|
||||
|
||||
symbols := make([]Symbol, symtab.Len()/Sym32Size)
|
||||
|
||||
i := 0
|
||||
var sym Sym32
|
||||
for symtab.Len() > 0 {
|
||||
binary.Read(symtab, f.ByteOrder, &sym)
|
||||
str, _ := getString(strdata, int(sym.Name))
|
||||
symbols[i].Name = str
|
||||
symbols[i].Info = sym.Info
|
||||
symbols[i].Other = sym.Other
|
||||
symbols[i].Section = SectionIndex(sym.Shndx)
|
||||
symbols[i].Value = uint64(sym.Value)
|
||||
symbols[i].Size = uint64(sym.Size)
|
||||
i++
|
||||
}
|
||||
|
||||
return symbols, strdata, nil
|
||||
}
|
||||
|
||||
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
|
||||
symtabSection := f.SectionByType(typ)
|
||||
if symtabSection == nil {
|
||||
return nil, nil, ErrNoSymbols
|
||||
}
|
||||
|
||||
data, err := symtabSection.Data()
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("cannot load symbol section")
|
||||
}
|
||||
symtab := bytes.NewReader(data)
|
||||
if symtab.Len()%Sym64Size != 0 {
|
||||
return nil, nil, errors.New("length of symbol section is not a multiple of Sym64Size")
|
||||
}
|
||||
|
||||
strdata, err := f.stringTable(symtabSection.Link)
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("cannot load string table section")
|
||||
}
|
||||
|
||||
// The first entry is all zeros.
|
||||
var skip [Sym64Size]byte
|
||||
symtab.Read(skip[:])
|
||||
|
||||
symbols := make([]Symbol, symtab.Len()/Sym64Size)
|
||||
|
||||
i := 0
|
||||
var sym Sym64
|
||||
for symtab.Len() > 0 {
|
||||
binary.Read(symtab, f.ByteOrder, &sym)
|
||||
str, _ := getString(strdata, int(sym.Name))
|
||||
symbols[i].Name = str
|
||||
symbols[i].NameIndex = sym.Name
|
||||
symbols[i].Info = sym.Info
|
||||
symbols[i].Other = sym.Other
|
||||
symbols[i].Section = SectionIndex(sym.Shndx)
|
||||
symbols[i].SectIndex = sym.Shndx
|
||||
symbols[i].Value = sym.Value
|
||||
symbols[i].Size = sym.Size
|
||||
i++
|
||||
}
|
||||
|
||||
return symbols, strdata, nil
|
||||
}
|
||||
|
||||
// getString extracts a string from an ELF string table.
|
||||
func getString(section []byte, start int) (string, bool) {
|
||||
if start < 0 || start >= len(section) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for end := start; end < len(section); end++ {
|
||||
if section[end] == 0 {
|
||||
return string(section[start:end]), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Section returns a section with the given name, or nil if no such
|
||||
// section exists.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DWARF - No idea what this does
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
dwarfSuffix := func(s *Section) string {
|
||||
switch {
|
||||
case strings.HasPrefix(s.Name, ".debug_"):
|
||||
return s.Name[7:]
|
||||
case strings.HasPrefix(s.Name, ".zdebug_"):
|
||||
return s.Name[8:]
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
// sectionData gets the data for s, checks its size, and
|
||||
// applies any applicable relations.
|
||||
sectionData := func(i int, s *Section) ([]byte, error) {
|
||||
b, err := s.Data()
|
||||
if err != nil && uint64(len(b)) < s.Size {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(b) >= 12 && string(b[:4]) == "ZLIB" {
|
||||
dlen := binary.BigEndian.Uint64(b[4:12])
|
||||
dbuf := make([]byte, dlen)
|
||||
r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.ReadFull(r, dbuf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = dbuf
|
||||
}
|
||||
|
||||
for _, r := range f.Sections {
|
||||
if r.Type != SHT_RELA && r.Type != SHT_REL {
|
||||
continue
|
||||
}
|
||||
if int(r.Info) != i {
|
||||
continue
|
||||
}
|
||||
rd, err := r.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = f.applyRelocations(b, rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// There are many other DWARF sections, but these
|
||||
// are the ones the debug/dwarf package uses.
|
||||
// Don't bother loading others.
|
||||
var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := dat[suffix]; !ok {
|
||||
continue
|
||||
}
|
||||
b, err := sectionData(i, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dat[suffix] = b
|
||||
}
|
||||
|
||||
d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for DWARF4 .debug_types sections.
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix != "types" {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := sectionData(i, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// Symbols returns the symbol table for f. The symbols will be listed in the order
|
||||
// they appear in f.
|
||||
//
|
||||
// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
|
||||
// After retrieving the symbols as symtab, an externally supplied index x
|
||||
// corresponds to symtab[x-1], not symtab[x].
|
||||
func (f *File) Symbols() ([]Symbol, error) {
|
||||
sym, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
return sym, err
|
||||
}
|
||||
|
||||
// DynamicSymbols returns the dynamic symbol table for f. The symbols
|
||||
// will be listed in the order they appear in f.
|
||||
//
|
||||
// For compatibility with Symbols, DynamicSymbols omits the null symbol at index 0.
|
||||
// After retrieving the symbols as symtab, an externally supplied index x
|
||||
// corresponds to symtab[x-1], not symtab[x].
|
||||
func (f *File) DynamicSymbols() ([]Symbol, error) {
|
||||
sym, _, err := f.getSymbols(SHT_DYNSYM)
|
||||
return sym, err
|
||||
}
|
||||
|
||||
type ImportedSymbol struct {
|
||||
Name string
|
||||
Version string
|
||||
Library string
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
// It does not return weak symbols.
|
||||
func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
|
||||
sym, str, err := f.getSymbols(SHT_DYNSYM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.gnuVersionInit(str)
|
||||
var all []ImportedSymbol
|
||||
for i, s := range sym {
|
||||
if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
|
||||
all = append(all, ImportedSymbol{Name: s.Name})
|
||||
f.gnuVersion(i, &all[len(all)-1])
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
type verneed struct {
|
||||
File string
|
||||
Name string
|
||||
}
|
||||
|
||||
// gnuVersionInit parses the GNU version tables
|
||||
// for use by calls to gnuVersion.
|
||||
func (f *File) gnuVersionInit(str []byte) {
|
||||
// Accumulate verneed information.
|
||||
vn := f.SectionByType(SHT_GNU_VERNEED)
|
||||
if vn == nil {
|
||||
return
|
||||
}
|
||||
d, _ := vn.Data()
|
||||
|
||||
var need []verneed
|
||||
i := 0
|
||||
for {
|
||||
if i+16 > len(d) {
|
||||
break
|
||||
}
|
||||
vers := f.ByteOrder.Uint16(d[i : i+2])
|
||||
if vers != 1 {
|
||||
break
|
||||
}
|
||||
cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
|
||||
fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
|
||||
aux := f.ByteOrder.Uint32(d[i+8 : i+12])
|
||||
next := f.ByteOrder.Uint32(d[i+12 : i+16])
|
||||
file, _ := getString(str, int(fileoff))
|
||||
|
||||
var name string
|
||||
j := i + int(aux)
|
||||
for c := 0; c < int(cnt); c++ {
|
||||
if j+16 > len(d) {
|
||||
break
|
||||
}
|
||||
// hash := f.ByteOrder.Uint32(d[j:j+4])
|
||||
// flags := f.ByteOrder.Uint16(d[j+4:j+6])
|
||||
other := f.ByteOrder.Uint16(d[j+6 : j+8])
|
||||
nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
|
||||
next := f.ByteOrder.Uint32(d[j+12 : j+16])
|
||||
name, _ = getString(str, int(nameoff))
|
||||
ndx := int(other)
|
||||
if ndx >= len(need) {
|
||||
a := make([]verneed, 2*(ndx+1))
|
||||
copy(a, need)
|
||||
need = a
|
||||
}
|
||||
|
||||
need[ndx] = verneed{file, name}
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
j += int(next)
|
||||
}
|
||||
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
i += int(next)
|
||||
}
|
||||
|
||||
// Versym parallels symbol table, indexing into verneed.
|
||||
vs := f.SectionByType(SHT_GNU_VERSYM)
|
||||
if vs == nil {
|
||||
return
|
||||
}
|
||||
d, _ = vs.Data()
|
||||
|
||||
f.gnuNeed = need
|
||||
f.gnuVersym = d
|
||||
}
|
||||
|
||||
// gnuVersion adds Library and Version information to sym,
|
||||
// which came from offset i of the symbol table.
|
||||
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
|
||||
// Each entry is two bytes.
|
||||
i = (i + 1) * 2
|
||||
if i >= len(f.gnuVersym) {
|
||||
return
|
||||
}
|
||||
j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
|
||||
if j < 2 || j >= len(f.gnuNeed) {
|
||||
return
|
||||
}
|
||||
n := &f.gnuNeed[j]
|
||||
sym.Library = n.File
|
||||
sym.Version = n.Name
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the names of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
func (f *File) ImportedLibraries() ([]string, error) {
|
||||
return f.DynString(DT_NEEDED)
|
||||
}
|
||||
|
||||
func (f *File) parseDynTags() error {
|
||||
s := f.SectionByType(SHT_DYNAMIC)
|
||||
if s == nil {
|
||||
return nil // nothing to do
|
||||
}
|
||||
|
||||
var m []DynTagValue
|
||||
d, err := s.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//fmt.Printf("%+v\nd: %x len(%d)\n", s, d, len(d))
|
||||
|
||||
r := bytes.NewBuffer(d)
|
||||
for {
|
||||
var t, v uint64
|
||||
if err := binary.Read(r, f.ByteOrder, &t); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := binary.Read(r, f.ByteOrder, &v); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
m = append(m, DynTagValue{Tag: DynTag(t), Value: v})
|
||||
//fmt.Printf("%x -> %x\n", t, v)
|
||||
}
|
||||
f.DynTags = m
|
||||
return nil
|
||||
}
|
||||
|
||||
// DynString returns the strings listed for the given tag in the file's dynamic
|
||||
// section.
|
||||
//
|
||||
// The tag must be one that takes string values: DT_NEEDED, DT_SONAME, DT_RPATH, or
|
||||
// DT_RUNPATH.
|
||||
func (f *File) DynString(tag DynTag) ([]string, error) {
|
||||
switch tag {
|
||||
case DT_NEEDED, DT_SONAME, DT_RPATH, DT_RUNPATH:
|
||||
default:
|
||||
return nil, fmt.Errorf("non-string-valued tag %v", tag)
|
||||
}
|
||||
|
||||
ds := f.SectionByType(SHT_DYNAMIC)
|
||||
if ds == nil {
|
||||
// not dynamic, so no libraries
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
str, err := f.stringTable(ds.Link)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var all []string
|
||||
for _, taggedValue := range f.DynTags {
|
||||
if taggedValue.Tag == tag {
|
||||
s, ok := getString(str, int(taggedValue.Value))
|
||||
if ok {
|
||||
all = append(all, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package elf
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// errorReader returns error from all operations.
|
||||
type errorReader struct {
|
||||
error
|
||||
}
|
||||
|
||||
func (r errorReader) Read(p []byte) (n int, err error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) Seek(offset int64, whence int) (int64, error) {
|
||||
return 0, r.error
|
||||
}
|
||||
|
||||
func (r errorReader) Close() error {
|
||||
return r.error
|
||||
}
|
||||
|
||||
// readSeekerFromReader converts an io.Reader into an io.ReadSeeker.
|
||||
// In general Seek may not be efficient, but it is optimized for
|
||||
// common cases such as seeking to the end to find the length of the
|
||||
// data.
|
||||
type readSeekerFromReader struct {
|
||||
reset func() (io.Reader, error)
|
||||
r io.Reader
|
||||
size int64
|
||||
offset int64
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) start() {
|
||||
x, err := r.reset()
|
||||
if err != nil {
|
||||
r.r = errorReader{err}
|
||||
} else {
|
||||
r.r = x
|
||||
}
|
||||
r.offset = 0
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
|
||||
if r.r == nil {
|
||||
r.start()
|
||||
}
|
||||
n, err = r.r.Read(p)
|
||||
r.offset += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
|
||||
var newOffset int64
|
||||
switch whence {
|
||||
case seekStart:
|
||||
newOffset = offset
|
||||
case seekCurrent:
|
||||
newOffset = r.offset + offset
|
||||
case seekEnd:
|
||||
newOffset = r.size + offset
|
||||
default:
|
||||
return 0, os.ErrInvalid
|
||||
}
|
||||
|
||||
switch {
|
||||
case newOffset == r.offset:
|
||||
return newOffset, nil
|
||||
|
||||
case newOffset < 0, newOffset > r.size:
|
||||
return 0, os.ErrInvalid
|
||||
|
||||
case newOffset == 0:
|
||||
r.r = nil
|
||||
|
||||
case newOffset == r.size:
|
||||
r.r = errorReader{io.EOF}
|
||||
|
||||
default:
|
||||
if newOffset < r.offset {
|
||||
// Restart at the beginning.
|
||||
r.start()
|
||||
}
|
||||
// Read until we reach offset.
|
||||
var buf [512]byte
|
||||
for r.offset < newOffset {
|
||||
b := buf[:]
|
||||
if newOffset-r.offset < int64(len(buf)) {
|
||||
b = buf[:newOffset-r.offset]
|
||||
}
|
||||
if _, err := r.Read(b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
r.offset = newOffset
|
||||
return r.offset, nil
|
||||
}
|
||||
-529
@@ -1,529 +0,0 @@
|
||||
package elf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// applyRelocations applies relocations to dst. rels is a relocations section
|
||||
// in REL or RELA format.
|
||||
func (f *File) applyRelocations(dst []byte, rels []byte) error {
|
||||
switch {
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
|
||||
return f.applyRelocationsAMD64(dst, rels)
|
||||
case f.Class == ELFCLASS32 && f.Machine == EM_386:
|
||||
return f.applyRelocations386(dst, rels)
|
||||
case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
|
||||
return f.applyRelocationsARM(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
|
||||
return f.applyRelocationsARM64(dst, rels)
|
||||
case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
|
||||
return f.applyRelocationsPPC(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
|
||||
return f.applyRelocationsPPC64(dst, rels)
|
||||
case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
|
||||
return f.applyRelocationsMIPS(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
|
||||
return f.applyRelocationsMIPS64(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_RISCV:
|
||||
return f.applyRelocationsRISCV64(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_S390:
|
||||
return f.applyRelocationss390x(dst, rels)
|
||||
case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
|
||||
return f.applyRelocationsSPARC64(dst, rels)
|
||||
default:
|
||||
return errors.New("applyRelocations: not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_X86_64(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
// There are relocations, so this must be a normal
|
||||
// object file, and we only look at section symbols,
|
||||
// so we assume that the symbol value is 0.
|
||||
|
||||
switch t {
|
||||
case R_X86_64_64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
|
||||
case R_X86_64_32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocations386(dst []byte, rels []byte) error {
|
||||
// 8 is the size of Rel32.
|
||||
if len(rels)%8 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 8")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rel Rel32
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rel)
|
||||
symNo := rel.Info >> 8
|
||||
t := R_386(rel.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint32(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
|
||||
if t == R_386_32 {
|
||||
if rel.Off+4 >= uint32(len(dst)) {
|
||||
continue
|
||||
}
|
||||
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
|
||||
val += uint32(sym.Value)
|
||||
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
|
||||
// 8 is the size of Rel32.
|
||||
if len(rels)%8 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 8")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rel Rel32
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rel)
|
||||
symNo := rel.Info >> 8
|
||||
t := R_ARM(rel.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint32(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
|
||||
switch t {
|
||||
case R_ARM_ABS32:
|
||||
if rel.Off+4 >= uint32(len(dst)) {
|
||||
continue
|
||||
}
|
||||
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
|
||||
val += uint32(sym.Value)
|
||||
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_AARCH64(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
// There are relocations, so this must be a normal
|
||||
// object file, and we only look at section symbols,
|
||||
// so we assume that the symbol value is 0.
|
||||
|
||||
switch t {
|
||||
case R_AARCH64_ABS64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
|
||||
case R_AARCH64_ABS32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
|
||||
// 12 is the size of Rela32.
|
||||
if len(rels)%12 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 12")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela32
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 8
|
||||
t := R_PPC(rela.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint32(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_PPC_ADDR32:
|
||||
if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_PPC64(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_PPC64_ADDR64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
|
||||
case R_PPC64_ADDR32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
|
||||
// 8 is the size of Rel32.
|
||||
if len(rels)%8 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 8")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rel Rel32
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rel)
|
||||
symNo := rel.Info >> 8
|
||||
t := R_MIPS(rel.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint32(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
|
||||
switch t {
|
||||
case R_MIPS_32:
|
||||
if rel.Off+4 >= uint32(len(dst)) {
|
||||
continue
|
||||
}
|
||||
val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
|
||||
val += uint32(sym.Value)
|
||||
f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
var symNo uint64
|
||||
var t R_MIPS
|
||||
if f.ByteOrder == binary.BigEndian {
|
||||
symNo = rela.Info >> 32
|
||||
t = R_MIPS(rela.Info & 0xff)
|
||||
} else {
|
||||
symNo = rela.Info & 0xffffffff
|
||||
t = R_MIPS(rela.Info >> 56)
|
||||
}
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_MIPS_64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
|
||||
case R_MIPS_32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsRISCV64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_RISCV(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
switch SymType(sym.Info & 0xf) {
|
||||
case STT_SECTION, STT_NOTYPE:
|
||||
break
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_RISCV_64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
val := sym.Value + uint64(rela.Addend)
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
|
||||
case R_RISCV_32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
val := uint32(sym.Value) + uint32(rela.Addend)
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_390(rela.Info & 0xffff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
switch SymType(sym.Info & 0xf) {
|
||||
case STT_SECTION, STT_NOTYPE:
|
||||
break
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_390_64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
val := sym.Value + uint64(rela.Addend)
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
|
||||
case R_390_32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
val := uint32(sym.Value) + uint32(rela.Addend)
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
|
||||
// 24 is the size of Rela64.
|
||||
if len(rels)%24 != 0 {
|
||||
return errors.New("length of relocation section is not a multiple of 24")
|
||||
}
|
||||
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b := bytes.NewReader(rels)
|
||||
var rela Rela64
|
||||
|
||||
for b.Len() > 0 {
|
||||
binary.Read(b, f.ByteOrder, &rela)
|
||||
symNo := rela.Info >> 32
|
||||
t := R_SPARC(rela.Info & 0xff)
|
||||
|
||||
if symNo == 0 || symNo > uint64(len(symbols)) {
|
||||
continue
|
||||
}
|
||||
sym := &symbols[symNo-1]
|
||||
if SymType(sym.Info&0xf) != STT_SECTION {
|
||||
// We don't handle non-section relocations for now.
|
||||
continue
|
||||
}
|
||||
|
||||
switch t {
|
||||
case R_SPARC_64, R_SPARC_UA64:
|
||||
if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
|
||||
case R_SPARC_32, R_SPARC_UA32:
|
||||
if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
|
||||
continue
|
||||
}
|
||||
f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-281
@@ -1,281 +0,0 @@
|
||||
package elf
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Bytes - returns the bytes of an Elf file
|
||||
func (elfFile *File) Bytes() ([]byte, error) {
|
||||
|
||||
bytesWritten := uint64(0)
|
||||
elfBuf := bytes.NewBuffer(nil)
|
||||
w := bufio.NewWriter(elfBuf)
|
||||
|
||||
// Write Elf Magic
|
||||
w.WriteByte('\x7f')
|
||||
w.WriteByte('E')
|
||||
w.WriteByte('L')
|
||||
w.WriteByte('F')
|
||||
bytesWritten += 4
|
||||
|
||||
// ident[EI_CLASS]
|
||||
w.WriteByte(byte(elfFile.Class))
|
||||
// ident[EI_DATA]
|
||||
w.WriteByte(byte(elfFile.Data))
|
||||
// ident[EI_VERSION]
|
||||
w.WriteByte(byte(elfFile.Version))
|
||||
// ident[EI_OSABI]
|
||||
w.WriteByte(byte(elfFile.OSABI))
|
||||
// ident[EI_ABIVERSION]
|
||||
w.WriteByte(byte(elfFile.ABIVersion))
|
||||
// ident[EI_PAD] ( 7 bytes )
|
||||
w.Write([]byte{0, 0, 0, 0, 0, 0, 0})
|
||||
bytesWritten += 12
|
||||
|
||||
// Type
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.Type))
|
||||
// Machine
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.Machine))
|
||||
// Version
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(elfFile.Version))
|
||||
bytesWritten += 8
|
||||
|
||||
phsize := 0
|
||||
|
||||
switch elfFile.Class {
|
||||
case ELFCLASS32:
|
||||
phsize = 0x20
|
||||
// Entry 32
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(elfFile.Entry))
|
||||
// PH Offset 32
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(0x34))
|
||||
// SH Offset 32 // 0x20 0x28 4 8 e_shoff Points to the start of the section header table.
|
||||
binary.Write(w, elfFile.ByteOrder, int32(elfFile.FileHeader.SHTOffset))
|
||||
// Flags
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(0)) // todo
|
||||
// EH Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(52))
|
||||
// PH Size // 0x2A 0x36 2 e_phentsize Contains the size of a program header table entry.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(phsize))
|
||||
// PH Num // 0x2C 0x38 2 e_phnum Contains the number of entries in the program header table.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Progs)))
|
||||
// SH Size // 0x2E 0x3A 2 e_shentsize Contains the size of a section header table entry.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(0x28))
|
||||
bytesWritten += 24
|
||||
|
||||
case ELFCLASS64:
|
||||
phsize = 0x38
|
||||
// Entry 64
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(elfFile.Entry))
|
||||
// PH Offset 64
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(0x40))
|
||||
// SH Offset 64 // 0x20 0x28 4 8 e_shoff Points to the start of the section header table.
|
||||
binary.Write(w, elfFile.ByteOrder, int64(elfFile.FileHeader.SHTOffset))
|
||||
// Flags
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(0)) // I think right?
|
||||
// EH Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(64))
|
||||
// PH Size // 0x2A 0x36 2 e_phentsize Contains the size of a program header table entry.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(phsize))
|
||||
// PH Num // 0x2C 0x38 2 e_phnum Contains the number of entries in the program header table.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Progs)))
|
||||
// SH Size // 0x2E 0x3A 2 e_shentsize Contains the size of a section header table entry.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(0x40))
|
||||
bytesWritten += 36
|
||||
}
|
||||
|
||||
// SH Num // 0x30 0x3C 2 e_shnum Contains the number of entries in the section header table.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(len(elfFile.Sections)))
|
||||
// SH Str Ndx // 0x32 0x3E 2 e_shstrndx Contains index of the section header table entry that contains the section names.
|
||||
binary.Write(w, elfFile.ByteOrder, uint16(elfFile.ShStrIndex))
|
||||
bytesWritten += 4
|
||||
|
||||
// Program Header
|
||||
for _, p := range elfFile.Progs {
|
||||
// Type (segment)
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Type))
|
||||
bytesWritten += 4
|
||||
|
||||
switch elfFile.Class {
|
||||
case ELFCLASS32:
|
||||
// Offset of Segment in File
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Off))
|
||||
|
||||
// Vaddr
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Vaddr))
|
||||
|
||||
// Paddr
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Paddr))
|
||||
|
||||
// File Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Filesz))
|
||||
|
||||
// Memory Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Memsz))
|
||||
|
||||
// Flags (segment)
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Flags))
|
||||
|
||||
// Alignment
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Align))
|
||||
|
||||
bytesWritten += 28
|
||||
|
||||
case ELFCLASS64:
|
||||
// Flags (segment)
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(p.Flags))
|
||||
|
||||
// Offset of Segment in File
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Off))
|
||||
|
||||
// Vaddr
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Vaddr))
|
||||
|
||||
// Paddr
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Paddr))
|
||||
|
||||
// File Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Filesz))
|
||||
|
||||
// Memory Size
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Memsz))
|
||||
|
||||
// Alignment
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(p.Align))
|
||||
|
||||
bytesWritten += 52
|
||||
}
|
||||
}
|
||||
|
||||
sortedSections := elfFile.Sections[:]
|
||||
//sort.Slice(sortedSections, func(a, b int) bool { return elfFile.Sections[a].Link < elfFile.Sections[b].Link })
|
||||
for _, s := range sortedSections {
|
||||
|
||||
//log.Printf("Writing section: %s type: %+v\n", s.Name, s.Type)
|
||||
//log.Printf("written: %x offset: %x\n", bytesWritten, s.Offset)
|
||||
|
||||
if s.Type == SHT_NULL || s.Type == SHT_NOBITS || s.FileSize == 0 {
|
||||
//log.Println("continuing...")
|
||||
continue
|
||||
}
|
||||
|
||||
if bytesWritten > s.Offset {
|
||||
log.Printf("Overlapping Sections in Generated Elf: %+v\n", s.Name)
|
||||
continue
|
||||
}
|
||||
if s.Offset != 0 && bytesWritten < s.Offset {
|
||||
pad := make([]byte, s.Offset-bytesWritten)
|
||||
w.Write(pad)
|
||||
//log.Printf("Padding before section %s at %x: length:%x to:%x\n", s.Name, bytesWritten, len(pad), s.Offset)
|
||||
bytesWritten += uint64(len(pad))
|
||||
}
|
||||
|
||||
slen := 0
|
||||
switch s.Type {
|
||||
case SHT_DYNAMIC:
|
||||
for _, taggedValue := range elfFile.DynTags {
|
||||
//log.Printf("writing %d (%x) -> %d (%x)\n", taggedValue.Tag, taggedValue.Tag, taggedValue.Value, taggedValue.Value)
|
||||
switch elfFile.Class {
|
||||
case ELFCLASS32:
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(taggedValue.Tag))
|
||||
binary.Write(w, elfFile.ByteOrder, uint32(taggedValue.Value))
|
||||
bytesWritten += 8
|
||||
case ELFCLASS64:
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(taggedValue.Tag))
|
||||
binary.Write(w, elfFile.ByteOrder, uint64(taggedValue.Value))
|
||||
bytesWritten += 16
|
||||
}
|
||||
}
|
||||
default:
|
||||
section, err := ioutil.ReadAll(s.Open())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
binary.Write(w, elfFile.ByteOrder, section)
|
||||
slen = len(section)
|
||||
//log.Printf("Wrote %s section at %x, length %x\n", s.Name, bytesWritten, slen)
|
||||
bytesWritten += uint64(slen)
|
||||
}
|
||||
|
||||
// todo: elfFile.Insertion should be renamed InsertionLoadEnd or similar
|
||||
if s.Type == SHT_PROGBITS && len(elfFile.Insertion) > 0 && s.Size-uint64(slen) >= uint64(len(elfFile.Insertion)) {
|
||||
binary.Write(w, elfFile.ByteOrder, elfFile.Insertion)
|
||||
bytesWritten += uint64(len(elfFile.Insertion))
|
||||
}
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
// Pad to Section Header Table
|
||||
if bytesWritten < uint64(elfFile.FileHeader.SHTOffset) {
|
||||
pad := make([]byte, uint64(elfFile.FileHeader.SHTOffset)-bytesWritten)
|
||||
w.Write(pad)
|
||||
//log.Printf("Padding before SHT at %x: length:%x to:%x\n", bytesWritten, len(pad), elfFile.FileHeader.SHTOffset)
|
||||
bytesWritten += uint64(len(pad))
|
||||
}
|
||||
|
||||
// Write Section Header Table
|
||||
|
||||
for _, s := range elfFile.Sections[:] {
|
||||
|
||||
switch elfFile.Class {
|
||||
case ELFCLASS32:
|
||||
binary.Write(w, elfFile.ByteOrder, &Section32{
|
||||
Name: s.Shname,
|
||||
Type: uint32(s.Type),
|
||||
Flags: uint32(s.Flags),
|
||||
Addr: uint32(s.Addr),
|
||||
Off: uint32(s.Offset),
|
||||
Size: uint32(s.Size),
|
||||
Link: s.Link,
|
||||
Info: s.Info,
|
||||
Addralign: uint32(s.Addralign),
|
||||
Entsize: uint32(s.Entsize)})
|
||||
case ELFCLASS64:
|
||||
binary.Write(w, elfFile.ByteOrder, &Section64{
|
||||
Name: s.Shname,
|
||||
Type: uint32(s.Type),
|
||||
Flags: uint64(s.Flags),
|
||||
Addr: s.Addr,
|
||||
Off: s.Offset,
|
||||
Size: s.Size,
|
||||
Link: s.Link,
|
||||
Info: s.Info,
|
||||
Addralign: s.Addralign,
|
||||
Entsize: s.Entsize})
|
||||
}
|
||||
}
|
||||
|
||||
// Do I have a PT_NOTE segment to add at the end?
|
||||
|
||||
if len(elfFile.InsertionEOF) > 0 {
|
||||
binary.Write(w, elfFile.ByteOrder, elfFile.InsertionEOF)
|
||||
bytesWritten += uint64(len(elfFile.InsertionEOF))
|
||||
}
|
||||
|
||||
w.Flush()
|
||||
return elfBuf.Bytes(), nil
|
||||
}
|
||||
|
||||
// WriteFile - Creates a new file and writes it using the Bytes func above
|
||||
func (elfFile *File) WriteFile(destFile string) error {
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
elfData, err := elfFile.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(elfData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
## More Info
|
||||
|
||||
More info on the Mach-O file structure here: [Mach-O Deep Dive](https://www.symbolcrash.com/2019/02/25/so-you-want-to-be-a-mach-o-man/)
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package macho
|
||||
|
||||
const N_SECT = 0x0E
|
||||
const N_PEXT = 0x10
|
||||
const N_EXT = 0x01
|
||||
|
||||
// Export - describes a single export entry (similar to PE version for future refactoring)
|
||||
type Export struct {
|
||||
//Ordinal uint32 // no ordinals for Mach-O
|
||||
Name string
|
||||
VirtualAddress uint64
|
||||
}
|
||||
|
||||
// Exports - gets exports, including private exports
|
||||
func (f *File) Exports() []Export {
|
||||
var exports []Export
|
||||
for _, symbol := range f.Symtab.Syms {
|
||||
if (symbol.Type&N_PEXT == N_PEXT ||
|
||||
symbol.Type&N_EXT == N_EXT) && symbol.Value != 0 {
|
||||
var export Export
|
||||
export.Name = symbol.Name
|
||||
export.VirtualAddress = symbol.Value
|
||||
exports = append(exports, export)
|
||||
}
|
||||
}
|
||||
return exports
|
||||
}
|
||||
-146
@@ -1,146 +0,0 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package macho
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A FatFile is a Mach-O universal binary that contains at least one architecture.
|
||||
type FatFile struct {
|
||||
Magic uint32
|
||||
Arches []FatArch
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// A FatArchHeader represents a fat header for a specific image architecture.
|
||||
type FatArchHeader struct {
|
||||
Cpu Cpu
|
||||
SubCpu uint32
|
||||
Offset uint32
|
||||
Size uint32
|
||||
Align uint32
|
||||
}
|
||||
|
||||
const fatArchHeaderSize = 5 * 4
|
||||
|
||||
// A FatArch is a Mach-O File inside a FatFile.
|
||||
type FatArch struct {
|
||||
FatArchHeader
|
||||
*File
|
||||
}
|
||||
|
||||
// ErrNotFat is returned from NewFatFile or OpenFat when the file is not a
|
||||
// universal binary but may be a thin binary, based on its magic number.
|
||||
var ErrNotFat = &FormatError{0, "not a fat Mach-O file", nil}
|
||||
|
||||
// NewFatFile creates a new FatFile for accessing all the Mach-O images in a
|
||||
// universal binary. The Mach-O binary is expected to start at position 0 in
|
||||
// the ReaderAt.
|
||||
func NewFatFile(r io.ReaderAt) (*FatFile, error) {
|
||||
var ff FatFile
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
|
||||
// Read the fat_header struct, which is always in big endian.
|
||||
// Start with the magic number.
|
||||
err := binary.Read(sr, binary.BigEndian, &ff.Magic)
|
||||
if err != nil {
|
||||
return nil, &FormatError{0, "error reading magic number", nil}
|
||||
} else if ff.Magic != MagicFat {
|
||||
// See if this is a Mach-O file via its magic number. The magic
|
||||
// must be converted to little endian first though.
|
||||
var buf [4]byte
|
||||
binary.BigEndian.PutUint32(buf[:], ff.Magic)
|
||||
leMagic := binary.LittleEndian.Uint32(buf[:])
|
||||
if leMagic == Magic32 || leMagic == Magic64 {
|
||||
return nil, ErrNotFat
|
||||
} else {
|
||||
return nil, &FormatError{0, "invalid magic number", nil}
|
||||
}
|
||||
}
|
||||
offset := int64(4)
|
||||
|
||||
// Read the number of FatArchHeaders that come after the fat_header.
|
||||
var narch uint32
|
||||
err = binary.Read(sr, binary.BigEndian, &narch)
|
||||
if err != nil {
|
||||
return nil, &FormatError{offset, "invalid fat_header", nil}
|
||||
}
|
||||
offset += 4
|
||||
|
||||
if narch < 1 {
|
||||
return nil, &FormatError{offset, "file contains no images", nil}
|
||||
}
|
||||
|
||||
// Combine the Cpu and SubCpu (both uint32) into a uint64 to make sure
|
||||
// there are not duplicate architectures.
|
||||
seenArches := make(map[uint64]bool, narch)
|
||||
// Make sure that all images are for the same MH_ type.
|
||||
var machoType Type
|
||||
|
||||
// Following the fat_header comes narch fat_arch structs that index
|
||||
// Mach-O images further in the file.
|
||||
ff.Arches = make([]FatArch, narch)
|
||||
for i := uint32(0); i < narch; i++ {
|
||||
fa := &ff.Arches[i]
|
||||
err = binary.Read(sr, binary.BigEndian, &fa.FatArchHeader)
|
||||
if err != nil {
|
||||
return nil, &FormatError{offset, "invalid fat_arch header", nil}
|
||||
}
|
||||
offset += fatArchHeaderSize
|
||||
|
||||
fr := io.NewSectionReader(r, int64(fa.Offset), int64(fa.Size))
|
||||
fa.File, err = NewFile(fr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure the architecture for this image is not duplicate.
|
||||
seenArch := (uint64(fa.Cpu) << 32) | uint64(fa.SubCpu)
|
||||
if o, k := seenArches[seenArch]; o || k {
|
||||
return nil, &FormatError{offset, fmt.Sprintf("duplicate architecture cpu=%v, subcpu=%#x", fa.Cpu, fa.SubCpu), nil}
|
||||
}
|
||||
seenArches[seenArch] = true
|
||||
|
||||
// Make sure the Mach-O type matches that of the first image.
|
||||
if i == 0 {
|
||||
machoType = fa.Type
|
||||
} else {
|
||||
if fa.Type != machoType {
|
||||
return nil, &FormatError{offset, fmt.Sprintf("Mach-O type for architecture #%d (type=%#x) does not match first (type=%#x)", i, fa.Type, machoType), nil}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &ff, nil
|
||||
}
|
||||
|
||||
// OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
|
||||
// universal binary.
|
||||
func OpenFat(name string) (*FatFile, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFatFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
func (ff *FatFile) Close() error {
|
||||
var err error
|
||||
if ff.closer != nil {
|
||||
err = ff.closer.Close()
|
||||
ff.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
-952
@@ -1,952 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package macho implements access to Mach-O object files.
|
||||
package macho
|
||||
|
||||
// High level access to low level data structures.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A File represents an open Mach-O file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
ByteOrder binary.ByteOrder
|
||||
Loads []Load
|
||||
Sections []*Section
|
||||
|
||||
Symtab *Symtab
|
||||
Dysymtab *Dysymtab
|
||||
SigBlock *SigBlock
|
||||
FuncStarts *FuncStarts
|
||||
DataInCode *DataInCode
|
||||
DylinkInfo *DylinkInfo
|
||||
|
||||
EntryPoint uint64
|
||||
Insertion []byte
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// A Load represents any Mach-O load command.
|
||||
type Load interface {
|
||||
Raw() []byte
|
||||
}
|
||||
|
||||
// A LoadBytes is the uninterpreted bytes of a Mach-O load command.
|
||||
type LoadBytes []byte
|
||||
|
||||
func (b LoadBytes) Raw() []byte { return b }
|
||||
|
||||
// A SegmentHeader is the header for a Mach-O 32-bit or 64-bit load segment command.
|
||||
type SegmentHeader struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Name string
|
||||
Addr uint64
|
||||
Memsz uint64
|
||||
Offset uint64
|
||||
Filesz uint64
|
||||
Maxprot uint32
|
||||
Prot uint32
|
||||
Nsect uint32
|
||||
Flag uint32
|
||||
}
|
||||
|
||||
type SigBlock struct {
|
||||
Len uint32
|
||||
Offset uint64
|
||||
RawDat []byte
|
||||
}
|
||||
|
||||
type FuncStarts struct {
|
||||
Len uint32
|
||||
Offset uint64
|
||||
RawDat []byte
|
||||
}
|
||||
|
||||
type DataInCode struct {
|
||||
Len uint32
|
||||
Offset uint64
|
||||
RawDat []byte
|
||||
}
|
||||
|
||||
type DylinkInfo struct {
|
||||
RebaseLen uint32
|
||||
RebaseOffset uint64
|
||||
RebaseDat []byte
|
||||
BindingInfoLen uint32
|
||||
BindingInfoOffset uint64
|
||||
BindingInfoDat []byte
|
||||
WeakBindingLen uint32
|
||||
WeakBindingOffset uint64
|
||||
WeakBindingDat []byte
|
||||
LazyBindingLen uint32
|
||||
LazyBindingOffset uint64
|
||||
LazyBindingDat []byte
|
||||
ExportInfoLen uint32
|
||||
ExportInfoOffset uint64
|
||||
ExportInfoDat []byte
|
||||
}
|
||||
|
||||
// A Segment represents a Mach-O 32-bit or 64-bit load segment command.
|
||||
type Segment struct {
|
||||
LoadBytes
|
||||
SegmentHeader
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the segment.
|
||||
func (s *Segment) Data() ([]byte, error) {
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
if n == len(dat) {
|
||||
err = nil
|
||||
}
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the segment.
|
||||
func (s *Segment) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
|
||||
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
Seg string
|
||||
Addr uint64
|
||||
Size uint64
|
||||
Offset uint32
|
||||
Align uint32
|
||||
Reloff uint32
|
||||
Nreloc uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// A Reloc represents a Mach-O relocation.
|
||||
type Reloc struct {
|
||||
Addr uint32
|
||||
Value uint32
|
||||
// when Scattered == false && Extern == true, Value is the symbol number.
|
||||
// when Scattered == false && Extern == false, Value is the section number.
|
||||
// when Scattered == true, Value is the value that this reloc refers to.
|
||||
Type uint8
|
||||
Len uint8 // 0=byte, 1=word, 2=long, 3=quad
|
||||
Pcrel bool
|
||||
Extern bool // valid if Scattered == false
|
||||
Scattered bool
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
Relocs []Reloc
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the Mach-O section.
|
||||
func (s *Section) Data() ([]byte, error) {
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
if n == len(dat) {
|
||||
err = nil
|
||||
}
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the Mach-O section.
|
||||
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
|
||||
|
||||
// A Dylinker represents a Mach-O load dynamic library command.
|
||||
type Dylinker struct {
|
||||
LoadBytes
|
||||
Name string
|
||||
}
|
||||
|
||||
// A Dylib represents a Mach-O load dynamic library command.
|
||||
type Dylib struct {
|
||||
LoadBytes
|
||||
Name string
|
||||
Time uint32
|
||||
CurrentVersion uint32
|
||||
CompatVersion uint32
|
||||
}
|
||||
|
||||
// A Symtab represents a Mach-O symbol table command.
|
||||
type Symtab struct {
|
||||
LoadBytes
|
||||
SymtabCmd
|
||||
Syms []Symbol
|
||||
RawSymtab []byte
|
||||
RawStringtab []byte
|
||||
}
|
||||
|
||||
// A Dysymtab represents a Mach-O dynamic symbol table command.
|
||||
type Dysymtab struct {
|
||||
LoadBytes
|
||||
DysymtabCmd
|
||||
IndirectSyms []uint32 // indices into Symtab.Syms
|
||||
RawDysymtab []byte
|
||||
}
|
||||
|
||||
// A Rpath represents a Mach-O rpath command.
|
||||
type Rpath struct {
|
||||
LoadBytes
|
||||
Path string
|
||||
}
|
||||
|
||||
// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Type uint8
|
||||
Sect uint8
|
||||
Desc uint16
|
||||
Value uint64
|
||||
}
|
||||
|
||||
/*
|
||||
* Mach-O reader
|
||||
*/
|
||||
|
||||
// FormatError is returned by some operations if the data does
|
||||
// not have the correct format for an object file.
|
||||
type FormatError struct {
|
||||
off int64
|
||||
msg string
|
||||
val interface{}
|
||||
}
|
||||
|
||||
func (e *FormatError) Error() string {
|
||||
msg := e.msg
|
||||
if e.val != nil {
|
||||
msg += fmt.Sprintf(" '%v'", e.val)
|
||||
}
|
||||
msg += fmt.Sprintf(" in record at byte %#x", e.off)
|
||||
return msg
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as a Mach-O binary.
|
||||
func Open(name string) (*File, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() error {
|
||||
var err error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// NewFile creates a new macho.File for accessing a Mach-o binary file in an underlying reader.
|
||||
func NewFile(r io.ReaderAt) (*File, error) {
|
||||
return newFileInternal(r, false)
|
||||
}
|
||||
|
||||
// NewFileFromMemory creates a new macho.File for accessing a Mach-O binary in-memory image in an underlying reader.
|
||||
func NewFileFromMemory(r io.ReaderAt) (*File, error) {
|
||||
return newFileInternal(r, true)
|
||||
}
|
||||
|
||||
// NewFile creates a new File for accessing a PE binary in an underlying reader.
|
||||
func newFileInternal(r io.ReaderAt, memoryMode bool) (*File, error) {
|
||||
|
||||
f := new(File)
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
|
||||
// Read and decode Mach magic to determine byte order, size.
|
||||
// Magic32 and Magic64 differ only in the bottom bit.
|
||||
var ident [4]byte
|
||||
if _, err := r.ReadAt(ident[0:], 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
be := binary.BigEndian.Uint32(ident[0:])
|
||||
le := binary.LittleEndian.Uint32(ident[0:])
|
||||
switch Magic32 &^ 1 {
|
||||
case be &^ 1:
|
||||
f.ByteOrder = binary.BigEndian
|
||||
f.Magic = be
|
||||
case le &^ 1:
|
||||
f.ByteOrder = binary.LittleEndian
|
||||
f.Magic = le
|
||||
default:
|
||||
return nil, &FormatError{0, "invalid magic number", nil}
|
||||
}
|
||||
|
||||
// Read entire file header.
|
||||
if err := binary.Read(sr, f.ByteOrder, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Then load commands.
|
||||
offset := int64(fileHeaderSize32)
|
||||
if f.Magic == Magic64 {
|
||||
offset = fileHeaderSize64
|
||||
}
|
||||
dat := make([]byte, f.Cmdsz)
|
||||
if _, err := r.ReadAt(dat, offset); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Loads = make([]Load, f.Ncmd)
|
||||
bo := f.ByteOrder
|
||||
for i := range f.Loads {
|
||||
// Each load command begins with uint32 command and length.
|
||||
if len(dat) < 8 {
|
||||
return nil, &FormatError{offset, "command block too small", nil}
|
||||
}
|
||||
cmd, siz := LoadCmd(bo.Uint32(dat[0:4])), bo.Uint32(dat[4:8])
|
||||
if siz < 8 || siz > uint32(len(dat)) {
|
||||
return nil, &FormatError{offset, "invalid command block size", nil}
|
||||
}
|
||||
var cmddat []byte
|
||||
cmddat, dat = dat[0:siz], dat[siz:]
|
||||
offset += int64(siz)
|
||||
var s *Segment
|
||||
//fmt.Printf("LoadCmdVal: %+v\n", cmd)
|
||||
switch cmd {
|
||||
default:
|
||||
f.Loads[i] = LoadBytes(cmddat)
|
||||
|
||||
case LoadCmdRpath:
|
||||
var hdr RpathCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := new(Rpath)
|
||||
if hdr.Path >= uint32(len(cmddat)) {
|
||||
return nil, &FormatError{offset, "invalid path in rpath command", hdr.Path}
|
||||
}
|
||||
l.Path = cstring(cmddat[hdr.Path:])
|
||||
l.LoadBytes = LoadBytes(cmddat)
|
||||
f.Loads[i] = l
|
||||
|
||||
case LoadCmdDylinker:
|
||||
var hdr DylinkerCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := new(Dylinker)
|
||||
if hdr.Name >= uint32(len(cmddat)) {
|
||||
return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
|
||||
}
|
||||
l.Name = cstring(cmddat[hdr.Name:])
|
||||
l.LoadBytes = LoadBytes(cmddat)
|
||||
f.Loads[i] = l
|
||||
|
||||
case LoadCmdDylib:
|
||||
var hdr DylibCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := new(Dylib)
|
||||
if hdr.Name >= uint32(len(cmddat)) {
|
||||
return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
|
||||
}
|
||||
l.Name = cstring(cmddat[hdr.Name:])
|
||||
l.Time = hdr.Time
|
||||
l.CurrentVersion = hdr.CurrentVersion
|
||||
l.CompatVersion = hdr.CompatVersion
|
||||
l.LoadBytes = LoadBytes(cmddat)
|
||||
f.Loads[i] = l
|
||||
|
||||
case LoadCmdSymtab:
|
||||
var hdr SymtabCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
strtab := make([]byte, hdr.Strsize)
|
||||
|
||||
var linkeditAddr, textAddr, linkeditOffset int64
|
||||
if !memoryMode {
|
||||
if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// in memory, we have to translate the file offsets for strtab/symtab into offsets into LINKEDIT segment
|
||||
for _, load := range f.Loads {
|
||||
switch segment := load.(type) {
|
||||
case *Segment:
|
||||
if segment == nil {
|
||||
continue
|
||||
}
|
||||
if segment.Name == "__LINKEDIT" {
|
||||
linkeditAddr = int64(segment.Addr)
|
||||
linkeditOffset = int64(segment.Offset)
|
||||
} else if segment.Name == "__TEXT" {
|
||||
textAddr = int64(segment.Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
strtabAddr := (linkeditAddr - textAddr) + (int64(hdr.Stroff) - linkeditOffset)
|
||||
if _, err := r.ReadAt(strtab, strtabAddr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var symsz int
|
||||
if f.Magic == Magic64 {
|
||||
symsz = 16
|
||||
} else {
|
||||
symsz = 12
|
||||
}
|
||||
symdat := make([]byte, int(hdr.Nsyms)*symsz)
|
||||
|
||||
if !memoryMode {
|
||||
if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if _, err := r.ReadAt(symdat, (linkeditAddr-textAddr)+(int64(hdr.Symoff)-linkeditOffset)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Loads[i] = st
|
||||
f.Symtab = st
|
||||
f.Symtab.Symoff = hdr.Symoff
|
||||
f.Symtab.Stroff = hdr.Stroff
|
||||
|
||||
case LoadCmdSignature:
|
||||
var sigCmd SigBlockCmd
|
||||
s := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(s, bo, &sigCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("SigData: %+v\n", sigCmd)
|
||||
sig := make([]byte, sigCmd.Sigsize)
|
||||
if _, err := r.ReadAt(sig, int64(sigCmd.Sigoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var block SigBlock
|
||||
block.Offset = uint64(sigCmd.Sigoff)
|
||||
block.Len = sigCmd.Sigsize
|
||||
block.RawDat = sig
|
||||
f.SigBlock = &block
|
||||
f.Loads[i] = LoadBytes(cmddat)
|
||||
|
||||
case LoadCmdFuncStarts:
|
||||
var funcCmd FuncStartsCmd
|
||||
fsc := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(fsc, bo, &funcCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("FuncStartsData: %+v\n", funcCmd)
|
||||
fs := make([]byte, funcCmd.Datasize)
|
||||
if _, err := r.ReadAt(fs, int64(funcCmd.Dataoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var funcs FuncStarts
|
||||
funcs.Offset = uint64(funcCmd.Dataoff)
|
||||
funcs.Len = funcCmd.Datasize
|
||||
funcs.RawDat = fs
|
||||
f.FuncStarts = &funcs
|
||||
f.Loads[i] = LoadBytes(cmddat)
|
||||
|
||||
case LoadCmdDataInCode:
|
||||
var dataCmd DataInCodeCmd
|
||||
dcc := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(dcc, bo, &dataCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("DataInCode: %+v\n", dataCmd)
|
||||
dc := make([]byte, dataCmd.Datasize)
|
||||
if _, err := r.ReadAt(dc, int64(dataCmd.Dataoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var datacode DataInCode
|
||||
datacode.Offset = uint64(dataCmd.Dataoff)
|
||||
datacode.Len = dataCmd.Datasize
|
||||
datacode.RawDat = dc
|
||||
f.DataInCode = &datacode
|
||||
f.Loads[i] = LoadBytes(cmddat)
|
||||
|
||||
case LoadCmdDylinkInfo:
|
||||
var dylinkInfoCmd DylinkInfoCmd
|
||||
dic := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(dic, bo, &dylinkInfoCmd); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//fmt.Printf("LoadCmdDylinkInfo: %+v\n", dylinkInfoCmd)
|
||||
// Copy each section next
|
||||
var dylinkInfo DylinkInfo
|
||||
// Rebase deets
|
||||
if dylinkInfoCmd.Rebasesize > 0 {
|
||||
if !memoryMode { // this data is in LINKEDIT already
|
||||
rebase := make([]byte, dylinkInfoCmd.Rebasesize)
|
||||
if _, err := r.ReadAt(rebase, int64(dylinkInfoCmd.Rebaseoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dylinkInfo.RebaseDat = rebase
|
||||
}
|
||||
dylinkInfo.RebaseLen = dylinkInfoCmd.Rebasesize
|
||||
dylinkInfo.RebaseOffset = uint64(dylinkInfoCmd.Rebaseoff)
|
||||
}
|
||||
// BindingInfo deets
|
||||
if dylinkInfoCmd.Bindinginfosize > 0 {
|
||||
if !memoryMode { // this data is in LINKEDIT already
|
||||
binding := make([]byte, dylinkInfoCmd.Bindinginfosize)
|
||||
if _, err := r.ReadAt(binding, int64(dylinkInfoCmd.Bindinginfooff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dylinkInfo.BindingInfoDat = binding
|
||||
}
|
||||
dylinkInfo.BindingInfoLen = dylinkInfoCmd.Bindinginfosize
|
||||
dylinkInfo.BindingInfoOffset = uint64(dylinkInfoCmd.Bindinginfooff)
|
||||
}
|
||||
// Weak deets
|
||||
if dylinkInfoCmd.Weakbindingsize > 0 {
|
||||
if !memoryMode { // this data is in LINKEDIT already
|
||||
weak := make([]byte, dylinkInfoCmd.Weakbindingsize)
|
||||
if _, err := r.ReadAt(weak, int64(dylinkInfoCmd.Weakbindingoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dylinkInfo.WeakBindingDat = weak
|
||||
}
|
||||
dylinkInfo.WeakBindingLen = dylinkInfoCmd.Weakbindingsize
|
||||
dylinkInfo.WeakBindingOffset = uint64(dylinkInfoCmd.Weakbindingoff)
|
||||
}
|
||||
// Lazy deets
|
||||
if dylinkInfoCmd.Lazybindingsize > 0 {
|
||||
if !memoryMode { // this data is in LINKEDIT already
|
||||
lazy := make([]byte, dylinkInfoCmd.Lazybindingsize)
|
||||
if _, err := r.ReadAt(lazy, int64(dylinkInfoCmd.Lazybindingoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dylinkInfo.LazyBindingDat = lazy
|
||||
}
|
||||
dylinkInfo.LazyBindingLen = dylinkInfoCmd.Lazybindingsize
|
||||
dylinkInfo.LazyBindingOffset = uint64(dylinkInfoCmd.Lazybindingoff)
|
||||
}
|
||||
// ExportInfo deets
|
||||
if dylinkInfoCmd.Exportinfosize > 0 {
|
||||
if !memoryMode { // this data is in LINKEDIT already
|
||||
export := make([]byte, dylinkInfoCmd.Exportinfosize)
|
||||
if _, err := r.ReadAt(export, int64(dylinkInfoCmd.Exportinfooff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dylinkInfo.ExportInfoDat = export
|
||||
}
|
||||
dylinkInfo.ExportInfoLen = dylinkInfoCmd.Exportinfosize
|
||||
dylinkInfo.ExportInfoOffset = uint64(dylinkInfoCmd.Exportinfooff)
|
||||
}
|
||||
// Finalize the object
|
||||
f.DylinkInfo = &dylinkInfo
|
||||
f.Loads[i] = LoadBytes(cmddat)
|
||||
|
||||
case LoadCmdDysymtab:
|
||||
var hdr DysymtabCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &hdr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dat := make([]byte, hdr.Nindirectsyms*4)
|
||||
if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := make([]uint32, hdr.Nindirectsyms)
|
||||
if err := binary.Read(bytes.NewReader(dat), bo, x); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st := new(Dysymtab)
|
||||
st.LoadBytes = LoadBytes(cmddat)
|
||||
st.DysymtabCmd = hdr
|
||||
st.IndirectSyms = x
|
||||
f.Loads[i] = st
|
||||
f.Dysymtab = st
|
||||
f.Dysymtab.Indirectsymoff = hdr.Indirectsymoff
|
||||
f.Dysymtab.RawDysymtab = dat
|
||||
|
||||
case LoadCmdSegment:
|
||||
var seg32 Segment32
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &seg32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s = new(Segment)
|
||||
s.LoadBytes = cmddat
|
||||
s.Cmd = cmd
|
||||
s.Len = siz
|
||||
s.Name = cstring(seg32.Name[0:])
|
||||
s.Addr = uint64(seg32.Addr)
|
||||
s.Memsz = uint64(seg32.Memsz)
|
||||
s.Offset = uint64(seg32.Offset)
|
||||
s.Filesz = uint64(seg32.Filesz)
|
||||
s.Maxprot = seg32.Maxprot
|
||||
s.Prot = seg32.Prot
|
||||
s.Nsect = seg32.Nsect
|
||||
s.Flag = seg32.Flag
|
||||
if uint64((seg32.Offset + seg32.Filesz)) > FinalSegEnd {
|
||||
FinalSegEnd = uint64((seg32.Offset + seg32.Filesz))
|
||||
}
|
||||
f.Loads[i] = s
|
||||
for i := 0; i < int(s.Nsect); i++ {
|
||||
var sh32 Section32
|
||||
if err := binary.Read(b, bo, &sh32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sh := new(Section)
|
||||
sh.Name = cstring(sh32.Name[0:])
|
||||
sh.Seg = cstring(sh32.Seg[0:])
|
||||
sh.Addr = uint64(sh32.Addr)
|
||||
sh.Size = uint64(sh32.Size)
|
||||
sh.Offset = sh32.Offset
|
||||
sh.Align = sh32.Align
|
||||
sh.Reloff = sh32.Reloff
|
||||
sh.Nreloc = sh32.Nreloc
|
||||
sh.Flags = sh32.Flags
|
||||
if err := f.pushSection(sh, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
case LoadCmdSegment64:
|
||||
var seg64 Segment64
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &seg64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s = new(Segment)
|
||||
s.LoadBytes = cmddat
|
||||
s.Cmd = cmd
|
||||
s.Len = siz
|
||||
s.Name = cstring(seg64.Name[0:])
|
||||
s.Addr = seg64.Addr
|
||||
s.Memsz = seg64.Memsz
|
||||
s.Offset = seg64.Offset
|
||||
s.Filesz = seg64.Filesz
|
||||
s.Maxprot = seg64.Maxprot
|
||||
s.Prot = seg64.Prot
|
||||
s.Nsect = seg64.Nsect
|
||||
s.Flag = seg64.Flag
|
||||
if uint64((seg64.Offset + seg64.Filesz)) > FinalSegEnd {
|
||||
FinalSegEnd = uint64((seg64.Offset + seg64.Filesz))
|
||||
}
|
||||
f.Loads[i] = s
|
||||
for i := 0; i < int(s.Nsect); i++ {
|
||||
var sh64 Section64
|
||||
if err := binary.Read(b, bo, &sh64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sh := new(Section)
|
||||
sh.Name = cstring(sh64.Name[0:])
|
||||
sh.Seg = cstring(sh64.Seg[0:])
|
||||
sh.Addr = sh64.Addr
|
||||
sh.Size = sh64.Size
|
||||
sh.Offset = sh64.Offset
|
||||
sh.Align = sh64.Align
|
||||
sh.Reloff = sh64.Reloff
|
||||
sh.Nreloc = sh64.Nreloc
|
||||
sh.Flags = sh64.Flags
|
||||
if err := f.pushSection(sh, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
//case LoadCmdUnixThread:
|
||||
// todo: do we have to support thread_command here for older binaries? or is the LC_MAIN handling backwards compatible?
|
||||
|
||||
case LoadCmdMain:
|
||||
var entryPoint EntryPointCmd
|
||||
b := bytes.NewReader(cmddat)
|
||||
if err := binary.Read(b, bo, &entryPoint); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.EntryPoint = entryPoint.EntryOff
|
||||
}
|
||||
if s != nil {
|
||||
if !memoryMode {
|
||||
s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.Filesz))
|
||||
} else {
|
||||
s.sr = io.NewSectionReader(r, int64(s.Addr), int64(s.Filesz))
|
||||
}
|
||||
s.ReaderAt = s.sr
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, error) {
|
||||
bo := f.ByteOrder
|
||||
symtab := make([]Symbol, hdr.Nsyms)
|
||||
b := bytes.NewReader(symdat)
|
||||
for i := range symtab {
|
||||
var n Nlist64
|
||||
if f.Magic == Magic64 {
|
||||
if err := binary.Read(b, bo, &n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
var n32 Nlist32
|
||||
if err := binary.Read(b, bo, &n32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n.Name = n32.Name
|
||||
n.Type = n32.Type
|
||||
n.Sect = n32.Sect
|
||||
n.Desc = n32.Desc
|
||||
n.Value = uint64(n32.Value)
|
||||
}
|
||||
sym := &symtab[i]
|
||||
if n.Name >= uint32(len(strtab)) {
|
||||
return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
|
||||
}
|
||||
sym.Name = cstring(strtab[n.Name:])
|
||||
sym.Type = n.Type
|
||||
sym.Sect = n.Sect
|
||||
sym.Desc = n.Desc
|
||||
sym.Value = n.Value
|
||||
}
|
||||
st := new(Symtab)
|
||||
st.LoadBytes = LoadBytes(cmddat)
|
||||
st.Syms = symtab
|
||||
st.RawSymtab = symdat
|
||||
st.RawStringtab = strtab
|
||||
return st, nil
|
||||
}
|
||||
|
||||
type relocInfo struct {
|
||||
Addr uint32
|
||||
Symnum uint32
|
||||
}
|
||||
|
||||
func (f *File) pushSection(sh *Section, r io.ReaderAt) error {
|
||||
f.Sections = append(f.Sections, sh)
|
||||
sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
|
||||
sh.ReaderAt = sh.sr
|
||||
|
||||
if sh.Nreloc > 0 {
|
||||
reldat := make([]byte, int(sh.Nreloc)*8)
|
||||
if _, err := r.ReadAt(reldat, int64(sh.Reloff)); err != nil {
|
||||
return err
|
||||
}
|
||||
b := bytes.NewReader(reldat)
|
||||
|
||||
bo := f.ByteOrder
|
||||
|
||||
sh.Relocs = make([]Reloc, sh.Nreloc)
|
||||
for i := range sh.Relocs {
|
||||
rel := &sh.Relocs[i]
|
||||
|
||||
var ri relocInfo
|
||||
if err := binary.Read(b, bo, &ri); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ri.Addr&(1<<31) != 0 { // scattered
|
||||
rel.Addr = ri.Addr & (1<<24 - 1)
|
||||
rel.Type = uint8((ri.Addr >> 24) & (1<<4 - 1))
|
||||
rel.Len = uint8((ri.Addr >> 28) & (1<<2 - 1))
|
||||
rel.Pcrel = ri.Addr&(1<<30) != 0
|
||||
rel.Value = ri.Symnum
|
||||
rel.Scattered = true
|
||||
} else {
|
||||
switch bo {
|
||||
case binary.LittleEndian:
|
||||
rel.Addr = ri.Addr
|
||||
rel.Value = ri.Symnum & (1<<24 - 1)
|
||||
rel.Pcrel = ri.Symnum&(1<<24) != 0
|
||||
rel.Len = uint8((ri.Symnum >> 25) & (1<<2 - 1))
|
||||
rel.Extern = ri.Symnum&(1<<27) != 0
|
||||
rel.Type = uint8((ri.Symnum >> 28) & (1<<4 - 1))
|
||||
case binary.BigEndian:
|
||||
rel.Addr = ri.Addr
|
||||
rel.Value = ri.Symnum >> 8
|
||||
rel.Pcrel = ri.Symnum&(1<<7) != 0
|
||||
rel.Len = uint8((ri.Symnum >> 5) & (1<<2 - 1))
|
||||
rel.Extern = ri.Symnum&(1<<4) != 0
|
||||
rel.Type = uint8(ri.Symnum & (1<<4 - 1))
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cstring(b []byte) string {
|
||||
i := bytes.IndexByte(b, 0)
|
||||
if i == -1 {
|
||||
i = len(b)
|
||||
}
|
||||
return string(b[0:i])
|
||||
}
|
||||
|
||||
// Segment returns the first Segment with the given name, or nil if no such segment exists.
|
||||
func (f *File) Segment(name string) *Segment {
|
||||
for _, l := range f.Loads {
|
||||
if s, ok := l.(*Segment); ok && s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Section returns the first section with the given name, or nil if no such
|
||||
// section exists.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DWARF returns the DWARF debug information for the Mach-O file.
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
dwarfSuffix := func(s *Section) string {
|
||||
switch {
|
||||
case strings.HasPrefix(s.Name, "__debug_"):
|
||||
return s.Name[8:]
|
||||
case strings.HasPrefix(s.Name, "__zdebug_"):
|
||||
return s.Name[9:]
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
sectionData := func(s *Section) ([]byte, error) {
|
||||
b, err := s.Data()
|
||||
if err != nil && uint64(len(b)) < s.Size {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(b) >= 12 && string(b[:4]) == "ZLIB" {
|
||||
dlen := binary.BigEndian.Uint64(b[4:12])
|
||||
dbuf := make([]byte, dlen)
|
||||
r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.ReadFull(r, dbuf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = dbuf
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// There are many other DWARF sections, but these
|
||||
// are the ones the debug/dwarf package uses.
|
||||
// Don't bother loading others.
|
||||
var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
|
||||
for _, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := dat[suffix]; !ok {
|
||||
continue
|
||||
}
|
||||
b, err := sectionData(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dat[suffix] = b
|
||||
}
|
||||
|
||||
d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for DWARF4 .debug_types sections.
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix != "types" {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := sectionData(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
func (f *File) ImportedSymbols() ([]string, error) {
|
||||
if f.Dysymtab == nil || f.Symtab == nil {
|
||||
return nil, &FormatError{0, "missing symbol table", nil}
|
||||
}
|
||||
|
||||
st := f.Symtab
|
||||
dt := f.Dysymtab
|
||||
var all []string
|
||||
for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
|
||||
all = append(all, s.Name)
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the paths of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
func (f *File) ImportedLibraries() ([]string, error) {
|
||||
var all []string
|
||||
for _, l := range f.Loads {
|
||||
if lib, ok := l.(*Dylib); ok {
|
||||
all = append(all, lib.Name)
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
-414
@@ -1,414 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Mach-O header data structures
|
||||
// http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
|
||||
|
||||
package macho
|
||||
|
||||
import "strconv"
|
||||
|
||||
// A FileHeader represents a Mach-O file header.
|
||||
type FileHeader struct {
|
||||
Magic uint32
|
||||
Cpu Cpu
|
||||
SubCpu uint32
|
||||
Type Type
|
||||
Ncmd uint32
|
||||
Cmdsz uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
const (
|
||||
fileHeaderSize32 = 7 * 4
|
||||
fileHeaderSize64 = 8 * 4
|
||||
)
|
||||
|
||||
const (
|
||||
Magic32 uint32 = 0xfeedface
|
||||
Magic64 uint32 = 0xfeedfacf
|
||||
MagicFat uint32 = 0xcafebabe
|
||||
)
|
||||
|
||||
// A Type is the Mach-O file type, e.g. an object file, executable, or dynamic library.
|
||||
type Type uint32
|
||||
|
||||
const (
|
||||
TypeObj Type = 1
|
||||
TypeExec Type = 2
|
||||
TypeDylib Type = 6
|
||||
TypeBundle Type = 8
|
||||
)
|
||||
|
||||
var typeStrings = []intName{
|
||||
{uint32(TypeObj), "Obj"},
|
||||
{uint32(TypeExec), "Exec"},
|
||||
{uint32(TypeDylib), "Dylib"},
|
||||
{uint32(TypeBundle), "Bundle"},
|
||||
}
|
||||
|
||||
func (t Type) String() string { return stringName(uint32(t), typeStrings, false) }
|
||||
func (t Type) GoString() string { return stringName(uint32(t), typeStrings, true) }
|
||||
|
||||
// A Cpu is a Mach-O cpu type.
|
||||
type Cpu uint32
|
||||
|
||||
const cpuArch64 = 0x01000000
|
||||
|
||||
const (
|
||||
Cpu386 Cpu = 7
|
||||
CpuAmd64 Cpu = Cpu386 | cpuArch64
|
||||
CpuArm Cpu = 12
|
||||
CpuArm64 Cpu = CpuArm | cpuArch64
|
||||
CpuPpc Cpu = 18
|
||||
CpuPpc64 Cpu = CpuPpc | cpuArch64
|
||||
)
|
||||
|
||||
var cpuStrings = []intName{
|
||||
{uint32(Cpu386), "Cpu386"},
|
||||
{uint32(CpuAmd64), "CpuAmd64"},
|
||||
{uint32(CpuArm), "CpuArm"},
|
||||
{uint32(CpuArm64), "CpuArm64"},
|
||||
{uint32(CpuPpc), "CpuPpc"},
|
||||
{uint32(CpuPpc64), "CpuPpc64"},
|
||||
}
|
||||
|
||||
var FinalSegEnd uint64
|
||||
|
||||
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
|
||||
func (i Cpu) GoString() string { return stringName(uint32(i), cpuStrings, true) }
|
||||
|
||||
// A LoadCmd is a Mach-O load command.
|
||||
type LoadCmd uint32
|
||||
|
||||
const (
|
||||
LoadCmdSegment LoadCmd = 0x1
|
||||
LoadCmdSymtab LoadCmd = 0x2
|
||||
LoadCmdThread LoadCmd = 0x4
|
||||
LoadCmdUnixThread LoadCmd = 0x5 // thread+stack
|
||||
LoadCmdDysymtab LoadCmd = 0xb
|
||||
LoadCmdDylib LoadCmd = 0xc // load dylib command
|
||||
LoadCmdDylinker LoadCmd = 0xf // id dylinker command (not load dylinker command)
|
||||
LoadCmdSegment64 LoadCmd = 0x19
|
||||
LoadCmdSignature LoadCmd = 0x1d
|
||||
LoadCmdFuncStarts LoadCmd = 0x26 // Function Starts
|
||||
LoadCmdDataInCode LoadCmd = 0x29 // Data In Code
|
||||
|
||||
LoadReqDyld LoadCmd = 0x80000000
|
||||
LoadCmdMain LoadCmd = (0x28 | LoadReqDyld) // replacement for LC_UNIXTHREAD
|
||||
LoadCmdRpath LoadCmd = 0x8000001c
|
||||
LoadCmdDylinkInfo LoadCmd = 0x80000022 // Dynamic Linker Info Only
|
||||
)
|
||||
|
||||
var cmdStrings = []intName{
|
||||
{uint32(LoadCmdSegment), "LoadCmdSegment"},
|
||||
{uint32(LoadCmdThread), "LoadCmdThread"},
|
||||
{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
|
||||
{uint32(LoadCmdDylib), "LoadCmdDylib"},
|
||||
{uint32(LoadCmdSegment64), "LoadCmdSegment64"},
|
||||
{uint32(LoadCmdRpath), "LoadCmdRpath"},
|
||||
{uint32(LoadCmdSignature), "LoadCmdSignature"},
|
||||
{uint32(LoadCmdFuncStarts), "LoadCmdFuncStarts"},
|
||||
{uint32(LoadCmdDataInCode), "LoadCmdDataInCode"},
|
||||
{uint32(LoadCmdDylinkInfo), "LoadCmdDylinkInfo"},
|
||||
}
|
||||
|
||||
func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
|
||||
func (i LoadCmd) GoString() string { return stringName(uint32(i), cmdStrings, true) }
|
||||
|
||||
// Prog.Flag
|
||||
type ProgFlag uint32
|
||||
|
||||
const (
|
||||
PF_NONE ProgFlag = 0x0 /* None */
|
||||
PF_R ProgFlag = 0x1 /* Readable. */
|
||||
PF_W ProgFlag = 0x2 /* Writable. */
|
||||
PF_X ProgFlag = 0x4 /* Executable. */
|
||||
)
|
||||
|
||||
type (
|
||||
// A Segment32 is a 32-bit Mach-O segment load command.
|
||||
Segment32 struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Name [16]byte
|
||||
Addr uint32
|
||||
Memsz uint32
|
||||
Offset uint32
|
||||
Filesz uint32
|
||||
Maxprot uint32 // ProgFlag - Maximum Segment Virtual Memory Protections
|
||||
Prot uint32 // ProgFlag - Initial Segment Virtual Memory Protections
|
||||
Nsect uint32
|
||||
Flag uint32
|
||||
}
|
||||
|
||||
// A Segment64 is a 64-bit Mach-O segment load command.
|
||||
Segment64 struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Name [16]byte
|
||||
Addr uint64
|
||||
Memsz uint64
|
||||
Offset uint64
|
||||
Filesz uint64
|
||||
Maxprot uint32
|
||||
Prot uint32
|
||||
Nsect uint32
|
||||
Flag uint32
|
||||
}
|
||||
|
||||
// A SigBlockCmd is a Mach-O symbol table command.
|
||||
SigBlockCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Sigoff uint32
|
||||
Sigsize uint32
|
||||
}
|
||||
|
||||
// A SymtabCmd is a Mach-O symbol table command.
|
||||
SymtabCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Symoff uint32
|
||||
Nsyms uint32
|
||||
Stroff uint32
|
||||
Strsize uint32
|
||||
}
|
||||
|
||||
// A DysymtabCmd is a Mach-O dynamic symbol table command.
|
||||
DysymtabCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Ilocalsym uint32
|
||||
Nlocalsym uint32
|
||||
Iextdefsym uint32
|
||||
Nextdefsym uint32
|
||||
Iundefsym uint32
|
||||
Nundefsym uint32
|
||||
Tocoffset uint32
|
||||
Ntoc uint32
|
||||
Modtaboff uint32
|
||||
Nmodtab uint32
|
||||
Extrefsymoff uint32
|
||||
Nextrefsyms uint32
|
||||
Indirectsymoff uint32
|
||||
Nindirectsyms uint32
|
||||
Extreloff uint32
|
||||
Nextrel uint32
|
||||
Locreloff uint32
|
||||
Nlocrel uint32
|
||||
}
|
||||
|
||||
// DylinkerCmd is a load command to identify the dynamic linker
|
||||
DylinkerCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Name uint32
|
||||
}
|
||||
|
||||
// A DylibCmd is a Mach-O load dynamic library command.
|
||||
DylibCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Name uint32
|
||||
Time uint32
|
||||
CurrentVersion uint32
|
||||
CompatVersion uint32
|
||||
}
|
||||
|
||||
// A FuncStartsCmd is a Mach-O load Function Starts command
|
||||
FuncStartsCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Dataoff uint32
|
||||
Datasize uint32
|
||||
}
|
||||
|
||||
// A DataInCodeCmd is a Mach-O load for Data In Code command
|
||||
DataInCodeCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Dataoff uint32
|
||||
Datasize uint32
|
||||
}
|
||||
|
||||
// A DylinkInfoCmd is a Mach-O load for Dynamic Linker Info Only Command
|
||||
DylinkInfoCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Rebaseoff uint32
|
||||
Rebasesize uint32
|
||||
Bindinginfooff uint32
|
||||
Bindinginfosize uint32
|
||||
Weakbindingoff uint32
|
||||
Weakbindingsize uint32
|
||||
Lazybindingoff uint32
|
||||
Lazybindingsize uint32
|
||||
Exportinfooff uint32
|
||||
Exportinfosize uint32
|
||||
}
|
||||
|
||||
// A RpathCmd is a Mach-O rpath command.
|
||||
RpathCmd struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Path uint32
|
||||
}
|
||||
|
||||
// A Thread is a Mach-O thread state command.
|
||||
Thread struct {
|
||||
Cmd LoadCmd
|
||||
Len uint32
|
||||
Type uint32
|
||||
Data []uint32
|
||||
}
|
||||
|
||||
// A EntryPointCmd is a Mach-O entry point command.
|
||||
EntryPointCmd struct {
|
||||
Cmd uint32 /* LC_MAIN only used in MH_EXECUTE filetypes */
|
||||
CmdSize uint32 /* 24 */
|
||||
EntryOff uint64 /* file (__TEXT) offset of main() */
|
||||
StackSize uint64 /* if not zero, initial stack size */
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
FlagNoUndefs uint32 = 0x1
|
||||
FlagIncrLink uint32 = 0x2
|
||||
FlagDyldLink uint32 = 0x4
|
||||
FlagBindAtLoad uint32 = 0x8
|
||||
FlagPrebound uint32 = 0x10
|
||||
FlagSplitSegs uint32 = 0x20
|
||||
FlagLazyInit uint32 = 0x40
|
||||
FlagTwoLevel uint32 = 0x80
|
||||
FlagForceFlat uint32 = 0x100
|
||||
FlagNoMultiDefs uint32 = 0x200
|
||||
FlagNoFixPrebinding uint32 = 0x400
|
||||
FlagPrebindable uint32 = 0x800
|
||||
FlagAllModsBound uint32 = 0x1000
|
||||
FlagSubsectionsViaSymbols uint32 = 0x2000
|
||||
FlagCanonical uint32 = 0x4000
|
||||
FlagWeakDefines uint32 = 0x8000
|
||||
FlagBindsToWeak uint32 = 0x10000
|
||||
FlagAllowStackExecution uint32 = 0x20000
|
||||
FlagRootSafe uint32 = 0x40000
|
||||
FlagSetuidSafe uint32 = 0x80000
|
||||
FlagNoReexportedDylibs uint32 = 0x100000
|
||||
FlagPIE uint32 = 0x200000
|
||||
FlagDeadStrippableDylib uint32 = 0x400000
|
||||
FlagHasTLVDescriptors uint32 = 0x800000
|
||||
FlagNoHeapExecution uint32 = 0x1000000
|
||||
FlagAppExtensionSafe uint32 = 0x2000000
|
||||
)
|
||||
|
||||
// A Section32 is a 32-bit Mach-O section header.
|
||||
type Section32 struct {
|
||||
Name [16]byte
|
||||
Seg [16]byte
|
||||
Addr uint32
|
||||
Size uint32
|
||||
Offset uint32
|
||||
Align uint32
|
||||
Reloff uint32
|
||||
Nreloc uint32
|
||||
Flags uint32
|
||||
Reserve1 uint32
|
||||
Reserve2 uint32
|
||||
}
|
||||
|
||||
// A Section64 is a 64-bit Mach-O section header.
|
||||
type Section64 struct {
|
||||
Name [16]byte
|
||||
Seg [16]byte
|
||||
Addr uint64
|
||||
Size uint64
|
||||
Offset uint32
|
||||
Align uint32
|
||||
Reloff uint32
|
||||
Nreloc uint32
|
||||
Flags uint32
|
||||
Reserve1 uint32
|
||||
Reserve2 uint32
|
||||
Reserve3 uint32
|
||||
}
|
||||
|
||||
// An Nlist32 is a Mach-O 32-bit symbol table entry.
|
||||
type Nlist32 struct {
|
||||
Name uint32
|
||||
Type uint8
|
||||
Sect uint8
|
||||
Desc uint16
|
||||
Value uint32
|
||||
}
|
||||
|
||||
// An Nlist64 is a Mach-O 64-bit symbol table entry.
|
||||
type Nlist64 struct {
|
||||
Name uint32
|
||||
Type uint8
|
||||
Sect uint8
|
||||
Desc uint16
|
||||
Value uint64
|
||||
}
|
||||
|
||||
// Regs386 is the Mach-O 386 register structure.
|
||||
type Regs386 struct {
|
||||
AX uint32
|
||||
BX uint32
|
||||
CX uint32
|
||||
DX uint32
|
||||
DI uint32
|
||||
SI uint32
|
||||
BP uint32
|
||||
SP uint32
|
||||
SS uint32
|
||||
FLAGS uint32
|
||||
IP uint32
|
||||
CS uint32
|
||||
DS uint32
|
||||
ES uint32
|
||||
FS uint32
|
||||
GS uint32
|
||||
}
|
||||
|
||||
// RegsAMD64 is the Mach-O AMD64 register structure.
|
||||
type RegsAMD64 struct {
|
||||
AX uint64
|
||||
BX uint64
|
||||
CX uint64
|
||||
DX uint64
|
||||
DI uint64
|
||||
SI uint64
|
||||
BP uint64
|
||||
SP uint64
|
||||
R8 uint64
|
||||
R9 uint64
|
||||
R10 uint64
|
||||
R11 uint64
|
||||
R12 uint64
|
||||
R13 uint64
|
||||
R14 uint64
|
||||
R15 uint64
|
||||
IP uint64
|
||||
FLAGS uint64
|
||||
CS uint64
|
||||
FS uint64
|
||||
GS uint64
|
||||
}
|
||||
|
||||
type intName struct {
|
||||
i uint32
|
||||
s string
|
||||
}
|
||||
|
||||
func stringName(i uint32, names []intName, goSyntax bool) string {
|
||||
for _, n := range names {
|
||||
if n.i == i {
|
||||
if goSyntax {
|
||||
return "macho." + n.s
|
||||
}
|
||||
return n.s
|
||||
}
|
||||
}
|
||||
return strconv.FormatUint(uint64(i), 10)
|
||||
}
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package macho
|
||||
|
||||
//go:generate stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go
|
||||
|
||||
type RelocTypeGeneric int
|
||||
|
||||
const (
|
||||
GENERIC_RELOC_VANILLA RelocTypeGeneric = 0
|
||||
GENERIC_RELOC_PAIR RelocTypeGeneric = 1
|
||||
GENERIC_RELOC_SECTDIFF RelocTypeGeneric = 2
|
||||
GENERIC_RELOC_PB_LA_PTR RelocTypeGeneric = 3
|
||||
GENERIC_RELOC_LOCAL_SECTDIFF RelocTypeGeneric = 4
|
||||
GENERIC_RELOC_TLV RelocTypeGeneric = 5
|
||||
)
|
||||
|
||||
func (r RelocTypeGeneric) GoString() string { return "macho." + r.String() }
|
||||
|
||||
type RelocTypeX86_64 int
|
||||
|
||||
const (
|
||||
X86_64_RELOC_UNSIGNED RelocTypeX86_64 = 0
|
||||
X86_64_RELOC_SIGNED RelocTypeX86_64 = 1
|
||||
X86_64_RELOC_BRANCH RelocTypeX86_64 = 2
|
||||
X86_64_RELOC_GOT_LOAD RelocTypeX86_64 = 3
|
||||
X86_64_RELOC_GOT RelocTypeX86_64 = 4
|
||||
X86_64_RELOC_SUBTRACTOR RelocTypeX86_64 = 5
|
||||
X86_64_RELOC_SIGNED_1 RelocTypeX86_64 = 6
|
||||
X86_64_RELOC_SIGNED_2 RelocTypeX86_64 = 7
|
||||
X86_64_RELOC_SIGNED_4 RelocTypeX86_64 = 8
|
||||
X86_64_RELOC_TLV RelocTypeX86_64 = 9
|
||||
)
|
||||
|
||||
func (r RelocTypeX86_64) GoString() string { return "macho." + r.String() }
|
||||
|
||||
type RelocTypeARM int
|
||||
|
||||
const (
|
||||
ARM_RELOC_VANILLA RelocTypeARM = 0
|
||||
ARM_RELOC_PAIR RelocTypeARM = 1
|
||||
ARM_RELOC_SECTDIFF RelocTypeARM = 2
|
||||
ARM_RELOC_LOCAL_SECTDIFF RelocTypeARM = 3
|
||||
ARM_RELOC_PB_LA_PTR RelocTypeARM = 4
|
||||
ARM_RELOC_BR24 RelocTypeARM = 5
|
||||
ARM_THUMB_RELOC_BR22 RelocTypeARM = 6
|
||||
ARM_THUMB_32BIT_BRANCH RelocTypeARM = 7
|
||||
ARM_RELOC_HALF RelocTypeARM = 8
|
||||
ARM_RELOC_HALF_SECTDIFF RelocTypeARM = 9
|
||||
)
|
||||
|
||||
func (r RelocTypeARM) GoString() string { return "macho." + r.String() }
|
||||
|
||||
type RelocTypeARM64 int
|
||||
|
||||
const (
|
||||
ARM64_RELOC_UNSIGNED RelocTypeARM64 = 0
|
||||
ARM64_RELOC_SUBTRACTOR RelocTypeARM64 = 1
|
||||
ARM64_RELOC_BRANCH26 RelocTypeARM64 = 2
|
||||
ARM64_RELOC_PAGE21 RelocTypeARM64 = 3
|
||||
ARM64_RELOC_PAGEOFF12 RelocTypeARM64 = 4
|
||||
ARM64_RELOC_GOT_LOAD_PAGE21 RelocTypeARM64 = 5
|
||||
ARM64_RELOC_GOT_LOAD_PAGEOFF12 RelocTypeARM64 = 6
|
||||
ARM64_RELOC_POINTER_TO_GOT RelocTypeARM64 = 7
|
||||
ARM64_RELOC_TLVP_LOAD_PAGE21 RelocTypeARM64 = 8
|
||||
ARM64_RELOC_TLVP_LOAD_PAGEOFF12 RelocTypeARM64 = 9
|
||||
ARM64_RELOC_ADDEND RelocTypeARM64 = 10
|
||||
)
|
||||
|
||||
func (r RelocTypeARM64) GoString() string { return "macho." + r.String() }
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
// Code generated by "stringer -type=RelocTypeGeneric,RelocTypeX86_64,RelocTypeARM,RelocTypeARM64 -output reloctype_string.go"; DO NOT EDIT.
|
||||
|
||||
package macho
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _RelocTypeGeneric_name = "GENERIC_RELOC_VANILLAGENERIC_RELOC_PAIRGENERIC_RELOC_SECTDIFFGENERIC_RELOC_PB_LA_PTRGENERIC_RELOC_LOCAL_SECTDIFFGENERIC_RELOC_TLV"
|
||||
|
||||
var _RelocTypeGeneric_index = [...]uint8{0, 21, 39, 61, 84, 112, 129}
|
||||
|
||||
func (i RelocTypeGeneric) String() string {
|
||||
if i < 0 || i >= RelocTypeGeneric(len(_RelocTypeGeneric_index)-1) {
|
||||
return "RelocTypeGeneric(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _RelocTypeGeneric_name[_RelocTypeGeneric_index[i]:_RelocTypeGeneric_index[i+1]]
|
||||
}
|
||||
|
||||
const _RelocTypeX86_64_name = "X86_64_RELOC_UNSIGNEDX86_64_RELOC_SIGNEDX86_64_RELOC_BRANCHX86_64_RELOC_GOT_LOADX86_64_RELOC_GOTX86_64_RELOC_SUBTRACTORX86_64_RELOC_SIGNED_1X86_64_RELOC_SIGNED_2X86_64_RELOC_SIGNED_4X86_64_RELOC_TLV"
|
||||
|
||||
var _RelocTypeX86_64_index = [...]uint8{0, 21, 40, 59, 80, 96, 119, 140, 161, 182, 198}
|
||||
|
||||
func (i RelocTypeX86_64) String() string {
|
||||
if i < 0 || i >= RelocTypeX86_64(len(_RelocTypeX86_64_index)-1) {
|
||||
return "RelocTypeX86_64(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _RelocTypeX86_64_name[_RelocTypeX86_64_index[i]:_RelocTypeX86_64_index[i+1]]
|
||||
}
|
||||
|
||||
const _RelocTypeARM_name = "ARM_RELOC_VANILLAARM_RELOC_PAIRARM_RELOC_SECTDIFFARM_RELOC_LOCAL_SECTDIFFARM_RELOC_PB_LA_PTRARM_RELOC_BR24ARM_THUMB_RELOC_BR22ARM_THUMB_32BIT_BRANCHARM_RELOC_HALFARM_RELOC_HALF_SECTDIFF"
|
||||
|
||||
var _RelocTypeARM_index = [...]uint8{0, 17, 31, 49, 73, 92, 106, 126, 148, 162, 185}
|
||||
|
||||
func (i RelocTypeARM) String() string {
|
||||
if i < 0 || i >= RelocTypeARM(len(_RelocTypeARM_index)-1) {
|
||||
return "RelocTypeARM(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _RelocTypeARM_name[_RelocTypeARM_index[i]:_RelocTypeARM_index[i+1]]
|
||||
}
|
||||
|
||||
const _RelocTypeARM64_name = "ARM64_RELOC_UNSIGNEDARM64_RELOC_SUBTRACTORARM64_RELOC_BRANCH26ARM64_RELOC_PAGE21ARM64_RELOC_PAGEOFF12ARM64_RELOC_GOT_LOAD_PAGE21ARM64_RELOC_GOT_LOAD_PAGEOFF12ARM64_RELOC_POINTER_TO_GOTARM64_RELOC_TLVP_LOAD_PAGE21ARM64_RELOC_TLVP_LOAD_PAGEOFF12ARM64_RELOC_ADDEND"
|
||||
|
||||
var _RelocTypeARM64_index = [...]uint16{0, 20, 42, 62, 80, 101, 128, 158, 184, 212, 243, 261}
|
||||
|
||||
func (i RelocTypeARM64) String() string {
|
||||
if i < 0 || i >= RelocTypeARM64(len(_RelocTypeARM64_index)-1) {
|
||||
return "RelocTypeARM64(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _RelocTypeARM64_name[_RelocTypeARM64_index[i]:_RelocTypeARM64_index[i+1]]
|
||||
}
|
||||
-343
@@ -1,343 +0,0 @@
|
||||
package macho
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Bytes - Returns the bytes of an assembled *macho.File
|
||||
func (machoFile *File) Bytes() ([]byte, error) {
|
||||
var bytesWritten uint64
|
||||
w := bytes.NewBuffer(nil)
|
||||
|
||||
// Write entire file header.
|
||||
buf := &bytes.Buffer{}
|
||||
err := binary.Write(buf, machoFile.ByteOrder, machoFile.FileHeader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
headerLength := len(buf.Bytes())
|
||||
binary.Write(w, machoFile.ByteOrder, machoFile.FileHeader)
|
||||
bytesWritten += uint64(headerLength)
|
||||
//log.Printf("%x: Wrote file header of size: %v", bytesWritten, bytesWritten)
|
||||
|
||||
// Reserved 4 bytes at end of header
|
||||
w.Write([]byte{0, 0, 0, 0})
|
||||
bytesWritten += 4
|
||||
|
||||
// Write Load Commands Loop
|
||||
for _, singleLoad := range machoFile.Loads {
|
||||
buf2 := &bytes.Buffer{}
|
||||
err = binary.Write(buf2, machoFile.ByteOrder, singleLoad.Raw())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
LoadCmdLen := len(buf2.Bytes())
|
||||
binary.Write(w, machoFile.ByteOrder, singleLoad.Raw())
|
||||
bytesWritten += uint64(LoadCmdLen)
|
||||
//log.Printf("%x: Wrote Load Command, total size of: %v", bytesWritten, LoadCmdLen)
|
||||
}
|
||||
|
||||
// Shellcode gets caved in between the final load command and the first section
|
||||
if len(machoFile.Insertion) > 0 {
|
||||
binary.Write(w, machoFile.ByteOrder, machoFile.Insertion)
|
||||
bytesWritten += uint64(len(machoFile.Insertion))
|
||||
}
|
||||
|
||||
// Sort Sections
|
||||
sortedSections := machoFile.Sections[:]
|
||||
sort.Slice(sortedSections, func(a, b int) bool { return machoFile.Sections[a].Offset < machoFile.Sections[b].Offset })
|
||||
|
||||
/*
|
||||
var caveOffset, caveSize uint64
|
||||
for _, s := range sortedSections {
|
||||
if s.SectionHeader.Seg == "__TEXT" && s.Name == "__text" {
|
||||
caveOffset = bytesWritten
|
||||
caveSize = uint64(s.Offset) - caveOffset
|
||||
log.Printf("Code Cave Size: %d - %d = %d\n", s.Offset, caveOffset, caveSize)
|
||||
log.Println("Shellcode Size: ", len(machoFile.Insertion))
|
||||
break
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Write Sections
|
||||
for _, s := range sortedSections {
|
||||
|
||||
if bytesWritten > uint64(s.Offset) {
|
||||
log.Printf("Overlapping Sections in Generated macho: %+v\n", s.Name)
|
||||
continue
|
||||
}
|
||||
if bytesWritten < uint64(s.Offset) {
|
||||
pad := make([]byte, uint64(s.Offset)-bytesWritten)
|
||||
w.Write(pad)
|
||||
bytesWritten += uint64(len(pad))
|
||||
//log.Printf("%x: wrote %d padding bytes\n", bytesWritten, len(pad))
|
||||
}
|
||||
section, err := ioutil.ReadAll(s.Open())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
binary.Write(w, machoFile.ByteOrder, section)
|
||||
bytesWritten += uint64(len(section))
|
||||
//log.Printf("%x: wrote %d bytes section/segment named: %s %s\n", bytesWritten, uint64(len(section)), s.Name, s.Seg)
|
||||
}
|
||||
// Write Dynamic Loader Info if it exists
|
||||
if machoFile.DylinkInfo != nil {
|
||||
// Write Rebase if it exists
|
||||
if len(machoFile.DylinkInfo.RebaseDat) > 0 {
|
||||
//log.Printf("Rebase Offset: %d", machoFile.DylinkInfo.RebaseOffset)
|
||||
if int64(machoFile.DylinkInfo.RebaseOffset)-int64(bytesWritten) > 0 {
|
||||
padA := make([]byte, machoFile.DylinkInfo.RebaseOffset-bytesWritten)
|
||||
w.Write(padA)
|
||||
bytesWritten += uint64(len(padA))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padA))
|
||||
}
|
||||
//log.Printf("Rebase: %+v \n", machoFile.DylinkInfo.RebaseDat)
|
||||
w.Write(machoFile.DylinkInfo.RebaseDat)
|
||||
bytesWritten += uint64(machoFile.DylinkInfo.RebaseLen)
|
||||
//log.Printf("%x: Wrote raw Rebase, length of: %d", bytesWritten, machoFile.DylinkInfo.RebaseLen)
|
||||
}
|
||||
//Binding
|
||||
if len(machoFile.DylinkInfo.BindingInfoDat) > 0 {
|
||||
//log.Printf("Binding Offset: %d", machoFile.DylinkInfo.BindingInfoOffset)
|
||||
if int64(machoFile.DylinkInfo.BindingInfoOffset)-int64(bytesWritten) > 0 {
|
||||
padB := make([]byte, machoFile.DylinkInfo.BindingInfoOffset-bytesWritten)
|
||||
w.Write(padB)
|
||||
bytesWritten += uint64(len(padB))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padB))
|
||||
}
|
||||
//log.Printf("Binding Info: %+v \n", machoFile.DylinkInfo.BindingInfoDat)
|
||||
w.Write(machoFile.DylinkInfo.BindingInfoDat)
|
||||
bytesWritten += uint64(machoFile.DylinkInfo.BindingInfoLen)
|
||||
//log.Printf("%x: Wrote raw Binding Info, length of: %d", bytesWritten, machoFile.DylinkInfo.BindingInfoLen)
|
||||
}
|
||||
//Lazy
|
||||
if len(machoFile.DylinkInfo.LazyBindingDat) > 0 {
|
||||
//log.Printf("Lazy Offset: %d", machoFile.DylinkInfo.LazyBindingOffset)
|
||||
if int64(machoFile.DylinkInfo.LazyBindingOffset)-int64(bytesWritten) > 0 {
|
||||
padD := make([]byte, machoFile.DylinkInfo.LazyBindingOffset-bytesWritten)
|
||||
w.Write(padD)
|
||||
bytesWritten += uint64(len(padD))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padD))
|
||||
}
|
||||
//log.Printf("Lazy Binding Data: %+v \n", machoFile.DylinkInfo.LazyBindingDat)
|
||||
w.Write(machoFile.DylinkInfo.LazyBindingDat)
|
||||
bytesWritten += uint64(machoFile.DylinkInfo.LazyBindingLen)
|
||||
//log.Printf("%x: Wrote raw lazybinding, length of: %d", bytesWritten, machoFile.DylinkInfo.LazyBindingLen)
|
||||
}
|
||||
//Export
|
||||
if len(machoFile.DylinkInfo.ExportInfoDat) > 0 {
|
||||
//log.Printf("Export Offset: %d", machoFile.DylinkInfo.ExportInfoOffset)
|
||||
if int64(machoFile.DylinkInfo.ExportInfoOffset)-int64(bytesWritten) > 0 {
|
||||
padE := make([]byte, machoFile.DylinkInfo.ExportInfoOffset-bytesWritten)
|
||||
w.Write(padE)
|
||||
bytesWritten += uint64(len(padE))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padE))
|
||||
}
|
||||
//log.Printf("Export Info: %+v \n", machoFile.DylinkInfo.ExportInfoDat)
|
||||
w.Write(machoFile.DylinkInfo.ExportInfoDat)
|
||||
bytesWritten += uint64(machoFile.DylinkInfo.ExportInfoLen)
|
||||
//log.Printf("%x: Wrote raw Export Info, length of: %d", bytesWritten, machoFile.DylinkInfo.ExportInfoLen)
|
||||
}
|
||||
//Weak
|
||||
if len(machoFile.DylinkInfo.WeakBindingDat) > 0 {
|
||||
//log.Printf("Weak Offset: %d", machoFile.DylinkInfo.WeakBindingOffset)
|
||||
if int64(machoFile.DylinkInfo.WeakBindingOffset)-int64(bytesWritten) > 0 {
|
||||
padC := make([]byte, machoFile.DylinkInfo.WeakBindingOffset-bytesWritten)
|
||||
w.Write(padC)
|
||||
bytesWritten += uint64(len(padC))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padC))
|
||||
}
|
||||
//log.Printf("Weak Binding: %+v \n", machoFile.DylinkInfo.WeakBindingDat)
|
||||
w.Write(machoFile.DylinkInfo.WeakBindingDat)
|
||||
bytesWritten += uint64(machoFile.DylinkInfo.WeakBindingLen)
|
||||
//log.Printf("%x: Wrote raw Weak Binding, length of: %d", bytesWritten, machoFile.DylinkInfo.WeakBindingLen)
|
||||
}
|
||||
}
|
||||
|
||||
// Write the Func Starts if they exist
|
||||
if machoFile.FuncStarts != nil {
|
||||
//log.Printf("new pad: %d", machoFile.FuncStarts.Offset-bytesWritten)
|
||||
if int64(machoFile.FuncStarts.Offset)-int64(bytesWritten) > 0 {
|
||||
padY := make([]byte, machoFile.FuncStarts.Offset-bytesWritten)
|
||||
w.Write(padY)
|
||||
bytesWritten += uint64(len(padY))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padY))
|
||||
}
|
||||
//log.Printf("FuncStarts: %+v \n", machoFile.FuncStarts)
|
||||
w.Write(machoFile.FuncStarts.RawDat)
|
||||
bytesWritten += uint64(machoFile.FuncStarts.Len)
|
||||
//log.Printf("%x: Wrote raw funcstarts, length of: %d", bytesWritten, machoFile.FuncStarts.Len)
|
||||
}
|
||||
|
||||
// Write the Data in Code Entries if they exist
|
||||
if machoFile.DataInCode != nil {
|
||||
if int64(machoFile.DataInCode.Offset)-int64(bytesWritten) > 0 {
|
||||
padZ := make([]byte, machoFile.DataInCode.Offset-bytesWritten)
|
||||
w.Write(padZ)
|
||||
bytesWritten += uint64(len(padZ))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padZ))
|
||||
}
|
||||
//log.Printf("DataInCode: %+v \n", machoFile.DataInCode)
|
||||
w.Write(machoFile.DataInCode.RawDat)
|
||||
bytesWritten += uint64(machoFile.DataInCode.Len)
|
||||
//log.Printf("%x: Wrote raw dataincode, length of: %d", bytesWritten, machoFile.DataInCode.Len)
|
||||
}
|
||||
|
||||
// Write Symbols is next I think
|
||||
symtab := machoFile.Symtab
|
||||
//log.Printf("Bytes written: %d", bytesWritten)
|
||||
//log.Printf("Indirect symbol offset: %d", machoFile.Dysymtab.DysymtabCmd.Indirectsymoff)
|
||||
//log.Printf("Locrel offset: %d", machoFile.Dysymtab.Locreloff)
|
||||
//log.Printf("Symtab offset: %d", symtab.Symoff)
|
||||
//log.Printf("String table offset: %d", symtab.Stroff)
|
||||
if int64(symtab.Symoff)-int64(bytesWritten) > 0 {
|
||||
pad := make([]byte, uint64(symtab.Symoff)-bytesWritten)
|
||||
w.Write(pad)
|
||||
bytesWritten += (uint64(symtab.Symoff) - bytesWritten)
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, uint64(symtab.Symoff)-bytesWritten)
|
||||
}
|
||||
w.Write(symtab.RawSymtab)
|
||||
bytesWritten += uint64(len(symtab.RawSymtab))
|
||||
//log.Printf("%x: Wrote raw symtab, length of: %d", bytesWritten, len(symtab.RawSymtab))
|
||||
|
||||
// Write DySymTab next!
|
||||
dysymtab := machoFile.Dysymtab
|
||||
if int64(dysymtab.Indirectsymoff)-int64(bytesWritten) > 0 {
|
||||
pad2 := make([]byte, uint64(dysymtab.Indirectsymoff)-bytesWritten)
|
||||
w.Write(pad2)
|
||||
bytesWritten += uint64(len(pad2))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(pad2))
|
||||
}
|
||||
w.Write(dysymtab.RawDysymtab)
|
||||
bytesWritten += uint64(len(dysymtab.RawDysymtab))
|
||||
//log.Printf("%x: Wrote raw indirect symbols, length of: %d", bytesWritten, len(dysymtab.RawDysymtab))
|
||||
|
||||
// Write StringTab!
|
||||
if int64(symtab.Stroff)-int64(bytesWritten) > 0 {
|
||||
pad3 := make([]byte, uint64(symtab.Stroff)-bytesWritten)
|
||||
w.Write(pad3)
|
||||
bytesWritten += uint64(len(pad3))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(pad3))
|
||||
}
|
||||
w.Write(symtab.RawStringtab)
|
||||
bytesWritten += uint64(len(symtab.RawStringtab))
|
||||
//log.Printf("%x: Wrote raw stringtab, length of: %d", bytesWritten, len(symtab.RawStringtab))
|
||||
|
||||
// Write The Signature Block, if it exists
|
||||
//log.Printf("SigBlock Dat: %v", machoFile.SigBlock)
|
||||
if machoFile.SigBlock != nil {
|
||||
if int64(machoFile.SigBlock.Offset)-int64(bytesWritten) > 0 {
|
||||
padX := make([]byte, int64(machoFile.SigBlock.Offset)-int64(bytesWritten))
|
||||
w.Write(padX)
|
||||
bytesWritten += uint64(len(padX))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(padX))
|
||||
}
|
||||
w.Write(machoFile.SigBlock.RawDat)
|
||||
bytesWritten += uint64(machoFile.SigBlock.Len)
|
||||
//log.Printf("%x: Wrote raw sigblock, length of: %d", bytesWritten, machoFile.SigBlock.Len)
|
||||
}
|
||||
|
||||
// Write 0s to the end of the final segment
|
||||
if int64(FinalSegEnd)-int64(bytesWritten) > 0 {
|
||||
pad4 := make([]byte, uint64(FinalSegEnd)-bytesWritten)
|
||||
w.Write(pad4)
|
||||
bytesWritten += uint64(len(pad4))
|
||||
//log.Printf("%x: wrote pad of: %d", bytesWritten, len(pad4))
|
||||
}
|
||||
|
||||
//log.Println("All done!")
|
||||
machoBytes := w.Bytes()
|
||||
return machoBytes, nil
|
||||
}
|
||||
|
||||
// WriteFile - Creates a new file and writes it using the Bytes func above
|
||||
func (machoFile *File) WriteFile(destFile string) error {
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
machoData, err := machoFile.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(machoData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteFatFile - Creates a new Fat file and multiple machos into it
|
||||
func (FatyFile *FatFile) WriteFatFile(destFile string) error {
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
w := bufio.NewWriter(f)
|
||||
bytesWritten := uint64(0)
|
||||
var FatyMachos []File
|
||||
var FatyMachosOffsets []uint32
|
||||
|
||||
// Fat Header First
|
||||
// Magic Bytes
|
||||
binary.Write(w, binary.BigEndian, FatyFile.Magic)
|
||||
bytesWritten += 4
|
||||
// Number of Fat Arches [4 bytes]
|
||||
FatArches := uint32(len(FatyFile.Arches))
|
||||
binary.Write(w, binary.BigEndian, FatArches)
|
||||
bytesWritten += 4
|
||||
w.Flush()
|
||||
// Arch Size
|
||||
for _, arch := range FatyFile.Arches {
|
||||
log.Printf("Arch details: %v\n", arch)
|
||||
FatyMachos = append(FatyMachos, *(arch.File))
|
||||
//Cpu Type
|
||||
binary.Write(w, binary.BigEndian, uint32(arch.Cpu))
|
||||
bytesWritten += 4
|
||||
//Sub CPU type
|
||||
binary.Write(w, binary.BigEndian, uint32(arch.SubCpu))
|
||||
bytesWritten += 4
|
||||
//FileOffset
|
||||
FatyMachosOffsets = append(FatyMachosOffsets, arch.Offset)
|
||||
binary.Write(w, binary.BigEndian, uint32(arch.Offset))
|
||||
bytesWritten += 4
|
||||
//Size
|
||||
binary.Write(w, binary.BigEndian, uint32(arch.Size))
|
||||
bytesWritten += 4
|
||||
//Align
|
||||
binary.Write(w, binary.BigEndian, uint32(arch.Align))
|
||||
bytesWritten += 4
|
||||
w.Flush()
|
||||
}
|
||||
// End of Fat Headers
|
||||
|
||||
// Write each Macho File at its Offset
|
||||
for index, mach := range FatyMachos {
|
||||
// Pad to the offset
|
||||
if bytesWritten < uint64(FatyMachosOffsets[index]) {
|
||||
pad := make([]byte, uint64(FatyMachosOffsets[index])-bytesWritten)
|
||||
w.Write(pad)
|
||||
bytesWritten += uint64(len(pad))
|
||||
}
|
||||
// Write the Mach-o file
|
||||
machOut, err := mach.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
binary.Write(w, binary.BigEndian, machOut)
|
||||
bytesWritten += uint64(len(machOut))
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// CERTIFICATE_TABLE is the index of the Certificate Table info in the Data Directory structure
|
||||
// in the PE header
|
||||
const CERTIFICATE_TABLE = 4
|
||||
|
||||
func readCertTable(f *File, r io.ReadSeeker) ([]byte, error) {
|
||||
if f.OptionalHeader == nil { // Optional header is optional, might not exist
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var certTableOffset, certTableSize uint32
|
||||
|
||||
switch f.FileHeader.Machine {
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
certTableOffset = f.OptionalHeader.(*OptionalHeader32).DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
||||
certTableSize = f.OptionalHeader.(*OptionalHeader32).DataDirectory[CERTIFICATE_TABLE].Size
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
certTableOffset = f.OptionalHeader.(*OptionalHeader64).DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
||||
certTableSize = f.OptionalHeader.(*OptionalHeader64).DataDirectory[CERTIFICATE_TABLE].Size
|
||||
default:
|
||||
return nil, errors.New("architecture not supported")
|
||||
}
|
||||
|
||||
// check if certificate table exists
|
||||
if certTableOffset == 0 || certTableSize == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
_, err = r.Seek(int64(certTableOffset), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to certificate table: %v", err)
|
||||
}
|
||||
|
||||
// grab the cert
|
||||
cert := make([]byte, certTableSize)
|
||||
_, err = io.ReadFull(r, cert)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read certificate table: %v", err)
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// ExportDirectory - data directory definition for exported functions
|
||||
type ExportDirectory struct {
|
||||
ExportFlags uint32 // reserved, must be zero
|
||||
TimeDateStamp uint32
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
NameRVA uint32 // pointer to the name of the DLL
|
||||
OrdinalBase uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32 // also Ordinal Table Len
|
||||
AddressTableAddr uint32 // RVA of EAT, relative to image base
|
||||
NameTableAddr uint32 // RVA of export name pointer table, relative to image base
|
||||
OrdinalTableAddr uint32 // address of the ordinal table, relative to iamge base
|
||||
|
||||
DllName string
|
||||
}
|
||||
|
||||
// Export - describes a single export entry
|
||||
type Export struct {
|
||||
Ordinal uint32
|
||||
Name string
|
||||
VirtualAddress uint32
|
||||
}
|
||||
|
||||
// Exports - gets exports
|
||||
func (f *File) Exports() ([]Export, error) {
|
||||
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
|
||||
// grab the number of data directory entries
|
||||
var ddLength uint32
|
||||
if pe64 {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader64).NumberOfRvaAndSizes
|
||||
} else {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader32).NumberOfRvaAndSizes
|
||||
}
|
||||
|
||||
// check that the length of data directory entries is large
|
||||
// enough to include the exports directory.
|
||||
if ddLength < IMAGE_DIRECTORY_ENTRY_EXPORT+1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// grab the export data directory entry
|
||||
var edd DataDirectory
|
||||
if pe64 {
|
||||
edd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
||||
} else {
|
||||
edd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
|
||||
}
|
||||
|
||||
// figure out which section contains the export directory table
|
||||
var ds *Section
|
||||
ds = nil
|
||||
for _, s := range f.Sections {
|
||||
if s.VirtualAddress <= edd.VirtualAddress && edd.VirtualAddress < s.VirtualAddress+s.VirtualSize {
|
||||
ds = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find a section, so no exports were found
|
||||
if ds == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
d, err := ds.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exportDirOffset := edd.VirtualAddress - ds.VirtualAddress
|
||||
|
||||
// seek to the virtual address specified in the export data directory
|
||||
dxd := d[exportDirOffset:]
|
||||
|
||||
// deserialize export directory
|
||||
var dt ExportDirectory
|
||||
dt.ExportFlags = binary.LittleEndian.Uint32(dxd[0:4])
|
||||
dt.TimeDateStamp = binary.LittleEndian.Uint32(dxd[4:8])
|
||||
dt.MajorVersion = binary.LittleEndian.Uint16(dxd[8:10])
|
||||
dt.MinorVersion = binary.LittleEndian.Uint16(dxd[10:12])
|
||||
dt.NameRVA = binary.LittleEndian.Uint32(dxd[12:16])
|
||||
dt.OrdinalBase = binary.LittleEndian.Uint32(dxd[16:20])
|
||||
dt.NumberOfFunctions = binary.LittleEndian.Uint32(dxd[20:24])
|
||||
dt.NumberOfNames = binary.LittleEndian.Uint32(dxd[24:28])
|
||||
dt.AddressTableAddr = binary.LittleEndian.Uint32(dxd[28:32])
|
||||
dt.NameTableAddr = binary.LittleEndian.Uint32(dxd[32:36])
|
||||
dt.OrdinalTableAddr = binary.LittleEndian.Uint32(dxd[36:40])
|
||||
|
||||
dt.DllName, _ = getString(d, int(dt.NameRVA-ds.VirtualAddress))
|
||||
|
||||
// seek to ordinal table
|
||||
dno := d[dt.OrdinalTableAddr-ds.VirtualAddress:]
|
||||
// seek to names table
|
||||
dnn := d[dt.NameTableAddr-ds.VirtualAddress:]
|
||||
|
||||
// build whole ordinal->name table
|
||||
ordinalTable := make(map[uint16]uint32)
|
||||
for n := uint32(0); n < dt.NumberOfNames; n++ {
|
||||
ord := binary.LittleEndian.Uint16(dno[n*2 : (n*2)+2])
|
||||
nameRVA := binary.LittleEndian.Uint32(dnn[n*4 : (n*4)+4])
|
||||
ordinalTable[ord] = nameRVA
|
||||
}
|
||||
dno = nil
|
||||
dnn = nil
|
||||
|
||||
// seek to ordinal table
|
||||
dna := d[dt.AddressTableAddr-ds.VirtualAddress:]
|
||||
|
||||
var exports []Export
|
||||
for i := uint32(0); i < dt.NumberOfFunctions; i++ {
|
||||
var export Export
|
||||
export.VirtualAddress =
|
||||
binary.LittleEndian.Uint32(dna[i*4 : (i*4)+4])
|
||||
export.Ordinal = dt.OrdinalBase + i
|
||||
|
||||
// check the entire ordinal table looking for this index to see if we have a name
|
||||
_, ok := ordinalTable[uint16(i)]
|
||||
if ok { // a name exists for this exported function
|
||||
nameRVA, _ := ordinalTable[uint16(i)]
|
||||
export.Name, _ = getString(d, int(nameRVA-ds.VirtualAddress))
|
||||
}
|
||||
exports = append(exports, export)
|
||||
}
|
||||
return exports, nil
|
||||
}
|
||||
-467
@@ -1,467 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
|
||||
package pe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap.
|
||||
const (
|
||||
seekStart = 0
|
||||
seekCurrent = 1
|
||||
)
|
||||
|
||||
// A File represents an open PE file.
|
||||
type File struct {
|
||||
DosHeader
|
||||
DosExists bool
|
||||
DosStub [64]byte // TODO(capnspacehook) make slice and correctly parse any DOS stub
|
||||
RichHeader []byte
|
||||
FileHeader
|
||||
OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
|
||||
Sections []*Section
|
||||
BaseRelocationTable *[]RelocationTableEntry
|
||||
Symbols []*Symbol // COFF symbols with auxiliary symbol records removed
|
||||
COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
|
||||
StringTable StringTable
|
||||
CertificateTable []byte
|
||||
|
||||
OptionalHeaderOffset int64 // offset of the start of the Optional Header
|
||||
InsertionAddr uint32
|
||||
InsertionBytes []byte
|
||||
|
||||
Net Net //If a managed executable, Net provides an interface to some of the metadata
|
||||
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// Open opens the named file using os.Open and prepares it for use as a PE binary.
|
||||
func Open(name string) (*File, error) {
|
||||
f, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ff, err := NewFile(f)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
ff.closer = f
|
||||
return ff, nil
|
||||
}
|
||||
|
||||
// Close closes the File.
|
||||
// If the File was created using NewFile directly instead of Open,
|
||||
// Close has no effect.
|
||||
func (f *File) Close() error {
|
||||
var err error
|
||||
if f.closer != nil {
|
||||
err = f.closer.Close()
|
||||
f.closer = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
sizeofOptionalHeader32 = uint16(binary.Size(OptionalHeader32{}))
|
||||
sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
|
||||
)
|
||||
|
||||
// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance)
|
||||
|
||||
// NewFile creates a new pe.File for accessing a PE binary file in an underlying reader.
|
||||
func NewFile(r io.ReaderAt) (*File, error) {
|
||||
return newFileInternal(r, false)
|
||||
}
|
||||
|
||||
// NewFileFromMemory creates a new pe.File for accessing a PE binary in-memory image in an underlying reader.
|
||||
func NewFileFromMemory(r io.ReaderAt) (*File, error) {
|
||||
return newFileInternal(r, true)
|
||||
}
|
||||
|
||||
// NewFile creates a new File for accessing a PE binary in an underlying reader.
|
||||
func newFileInternal(r io.ReaderAt, memoryMode bool) (*File, error) {
|
||||
|
||||
f := new(File)
|
||||
sr := io.NewSectionReader(r, 0, 1<<63-1)
|
||||
|
||||
binary.Read(sr, binary.LittleEndian, &f.DosHeader)
|
||||
dosHeaderSize := binary.Size(f.DosHeader)
|
||||
if dosHeaderSize > int(f.DosHeader.AddressOfNewExeHeader) {
|
||||
binary.Read(sr, binary.LittleEndian, &f.DosStub)
|
||||
f.DosExists = true
|
||||
} else {
|
||||
f.DosExists = false
|
||||
}
|
||||
|
||||
possibleRichHeaderStart := dosHeaderSize
|
||||
if f.DosExists {
|
||||
possibleRichHeaderStart += binary.Size(f.DosStub)
|
||||
}
|
||||
possibleRichHeaderEnd := int(f.DosHeader.AddressOfNewExeHeader)
|
||||
if possibleRichHeaderEnd > possibleRichHeaderStart {
|
||||
richHeader := make([]byte, possibleRichHeaderEnd-possibleRichHeaderStart)
|
||||
binary.Read(sr, binary.LittleEndian, richHeader)
|
||||
|
||||
if richIndex := bytes.Index(richHeader, []byte("Rich")); richIndex != -1 {
|
||||
f.RichHeader = richHeader[:richIndex+8]
|
||||
}
|
||||
}
|
||||
|
||||
var peHeaderOffset int64
|
||||
if f.DosHeader.MZSignature == 0x5a4d {
|
||||
peHeaderOffset = int64(f.DosHeader.AddressOfNewExeHeader)
|
||||
var sign [4]byte
|
||||
r.ReadAt(sign[:], peHeaderOffset)
|
||||
if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
|
||||
return nil, fmt.Errorf("Invalid PE COFF file signature of %v", sign)
|
||||
}
|
||||
peHeaderOffset += int64(4)
|
||||
} else {
|
||||
peHeaderOffset = int64(0)
|
||||
}
|
||||
|
||||
sr.Seek(peHeaderOffset, seekStart)
|
||||
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch f.FileHeader.Machine {
|
||||
case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386:
|
||||
default:
|
||||
return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x", f.FileHeader.Machine)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if memoryMode {
|
||||
//get strings table location - offset is wrong in the header because we are in memory mode. Can we fix it? Yes we can!
|
||||
restore, err := sr.Seek(0, seekCurrent)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Had a bad time getting restore point: %v", err)
|
||||
}
|
||||
//seek to table start (skip the headers)
|
||||
sr.Seek(peHeaderOffset+int64(binary.Size(f.FileHeader))+int64(f.FileHeader.SizeOfOptionalHeader), seekStart)
|
||||
|
||||
//iterate through the sections to find the raw offset value that matches the original symbol table value
|
||||
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
|
||||
sh := new(SectionHeader32)
|
||||
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//original offset matches the pointer to the symbol table, update the header so other things can reference it good again
|
||||
if sh.PointerToRawData == f.FileHeader.PointerToSymbolTable {
|
||||
f.FileHeader.PointerToSymbolTable = sh.VirtualAddress
|
||||
}
|
||||
}
|
||||
//restore the original location of sr (this shouldn't actually be required, but just in case)
|
||||
sr.Seek(restore, seekStart)
|
||||
}
|
||||
|
||||
// Read string table.
|
||||
f.StringTable, err = readStringTable(&f.FileHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read symbol table.
|
||||
f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read optional header.
|
||||
f.OptionalHeaderOffset = peHeaderOffset + int64(binary.Size(f.FileHeader))
|
||||
sr.Seek(f.OptionalHeaderOffset, seekStart)
|
||||
|
||||
var oh32 OptionalHeader32
|
||||
var oh64 OptionalHeader64
|
||||
switch f.FileHeader.SizeOfOptionalHeader {
|
||||
case sizeofOptionalHeader32:
|
||||
if err := binary.Read(sr, binary.LittleEndian, &oh32); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oh32.Magic != 0x10b { // PE32
|
||||
return nil, fmt.Errorf("pe32 optional header has unexpected Magic of 0x%x", oh32.Magic)
|
||||
}
|
||||
f.OptionalHeader = &oh32
|
||||
case sizeofOptionalHeader64:
|
||||
if err := binary.Read(sr, binary.LittleEndian, &oh64); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if oh64.Magic != 0x20b { // PE32+
|
||||
return nil, fmt.Errorf("pe32+ optional header has unexpected Magic of 0x%x", oh64.Magic)
|
||||
}
|
||||
f.OptionalHeader = &oh64
|
||||
}
|
||||
|
||||
// Process sections.
|
||||
f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
|
||||
for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
|
||||
sh := new(SectionHeader32)
|
||||
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name, err := sh.fullName(f.StringTable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := new(Section)
|
||||
s.SectionHeader = SectionHeader{
|
||||
Name: name,
|
||||
OriginalName: sh.Name,
|
||||
VirtualSize: sh.VirtualSize,
|
||||
VirtualAddress: sh.VirtualAddress,
|
||||
Size: sh.SizeOfRawData,
|
||||
Offset: sh.PointerToRawData,
|
||||
PointerToRelocations: sh.PointerToRelocations,
|
||||
PointerToLineNumbers: sh.PointerToLineNumbers,
|
||||
NumberOfRelocations: sh.NumberOfRelocations,
|
||||
NumberOfLineNumbers: sh.NumberOfLineNumbers,
|
||||
Characteristics: sh.Characteristics,
|
||||
}
|
||||
r2 := r
|
||||
if sh.PointerToRawData == 0 { // .bss must have all 0s
|
||||
r2 = zeroReaderAt{}
|
||||
}
|
||||
if !memoryMode {
|
||||
s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
|
||||
} else {
|
||||
s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.VirtualAddress), int64(s.SectionHeader.Size))
|
||||
}
|
||||
s.ReaderAt = s.sr
|
||||
f.Sections[i] = s
|
||||
}
|
||||
for i := range f.Sections {
|
||||
var err error
|
||||
f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Read Base Relocation Block and Items
|
||||
f.BaseRelocationTable, err = f.readBaseRelocationTable()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Read certificate table
|
||||
f.CertificateTable, err = readCertTable(f, sr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//fill net info
|
||||
if f.IsManaged() {
|
||||
var va, size uint32
|
||||
|
||||
//determine location of the COM descriptor directory
|
||||
switch v := f.OptionalHeader.(type) {
|
||||
case *OptionalHeader32:
|
||||
va = v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress
|
||||
size = v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size
|
||||
case *OptionalHeader64:
|
||||
va = v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress
|
||||
size = v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size
|
||||
}
|
||||
|
||||
//I'm unsure how to get a reader (not a readerat) for a particular thing, so copying buffers around.. this could be more optimal
|
||||
buff := make([]byte, size)
|
||||
|
||||
//none of these reads have errors being caught either, which is probably not ideal
|
||||
if !memoryMode {
|
||||
r.ReadAt(buff, int64(f.RVAToFileOffset(va)))
|
||||
} else {
|
||||
r.ReadAt(buff, int64(va))
|
||||
}
|
||||
binary.Read(bytes.NewReader(buff), binary.LittleEndian, &f.Net.NetDirectory)
|
||||
|
||||
//Now that we have the COR20 header (COM descriptor directory header), we can get the metadata section header, which has the version
|
||||
buff = make([]byte, f.Net.NetDirectory.MetaDataSize)
|
||||
//again, none of the reads are error checked :shrug:
|
||||
if !memoryMode {
|
||||
r.ReadAt(buff, int64(f.RVAToFileOffset(f.Net.NetDirectory.MetaDataRVA)))
|
||||
} else {
|
||||
r.ReadAt(buff, int64(f.Net.NetDirectory.MetaDataRVA))
|
||||
}
|
||||
f.Net.MetaData, _ = newMetadataHeader(bytes.NewReader(buff))
|
||||
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// zeroReaderAt is ReaderAt that reads 0s.
|
||||
type zeroReaderAt struct{}
|
||||
|
||||
// ReadAt writes len(p) 0s into p.
|
||||
func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = 0
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// getString extracts a string from symbol string table.
|
||||
func getString(section []byte, start int) (string, bool) {
|
||||
if start < 0 || start >= len(section) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for end := start; end < len(section); end++ {
|
||||
if section[end] == 0 {
|
||||
return string(section[start:end]), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Section returns the first section with the given name, or nil if no such
|
||||
// section exists.
|
||||
func (f *File) Section(name string) *Section {
|
||||
for _, s := range f.Sections {
|
||||
if s.Name == name {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
dwarfSuffix := func(s *Section) string {
|
||||
switch {
|
||||
case strings.HasPrefix(s.Name, ".debug_"):
|
||||
return s.Name[7:]
|
||||
case strings.HasPrefix(s.Name, ".zdebug_"):
|
||||
return s.Name[8:]
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// sectionData gets the data for s and checks its size.
|
||||
sectionData := func(s *Section) ([]byte, error) {
|
||||
b, err := s.Data()
|
||||
if err != nil && uint32(len(b)) < s.Size {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if 0 < s.VirtualSize && s.VirtualSize < s.Size {
|
||||
b = b[:s.VirtualSize]
|
||||
}
|
||||
|
||||
if len(b) >= 12 && string(b[:4]) == "ZLIB" {
|
||||
dlen := binary.BigEndian.Uint64(b[4:12])
|
||||
dbuf := make([]byte, dlen)
|
||||
r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.ReadFull(r, dbuf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := r.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b = dbuf
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// There are many other DWARF sections, but these
|
||||
// are the ones the debug/dwarf package uses.
|
||||
// Don't bother loading others.
|
||||
var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
|
||||
for _, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := dat[suffix]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := sectionData(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dat[suffix] = b
|
||||
}
|
||||
|
||||
d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Look for DWARF4 .debug_types sections.
|
||||
for i, s := range f.Sections {
|
||||
suffix := dwarfSuffix(s)
|
||||
if suffix != "types" {
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := sectionData(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// FormatError is unused.
|
||||
// The type is retained for compatibility.
|
||||
type FormatError struct {
|
||||
}
|
||||
|
||||
func (e *FormatError) Error() string {
|
||||
return "unknown error"
|
||||
}
|
||||
|
||||
//RVAToFileOffset Converts a Relative offset to the actual offset in the file.
|
||||
func (f *File) RVAToFileOffset(rva uint32) uint32 {
|
||||
var offset uint32
|
||||
for _, section := range f.Sections {
|
||||
if rva >= section.SectionHeader.VirtualAddress && rva <= section.SectionHeader.VirtualAddress+section.SectionHeader.Size {
|
||||
offset = section.SectionHeader.Offset + (rva - section.SectionHeader.VirtualAddress)
|
||||
}
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
//IsManaged returns true if the loaded PE file references the CLR header (aka is a .net exe)
|
||||
func (f *File) IsManaged() bool {
|
||||
switch v := f.OptionalHeader.(type) {
|
||||
case *OptionalHeader32:
|
||||
if v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != 0 {
|
||||
return true
|
||||
}
|
||||
case *OptionalHeader64:
|
||||
if v.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
-196
@@ -1,196 +0,0 @@
|
||||
package pe
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// ImportDirectory entry
|
||||
type ImportDirectory struct {
|
||||
OriginalFirstThunk uint32
|
||||
TimeDateStamp uint32
|
||||
ForwarderChain uint32
|
||||
NameRVA uint32
|
||||
FirstThunk uint32
|
||||
|
||||
DllName string
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
// It does not return weak symbols.
|
||||
func (f *File) ImportedSymbols() ([]string, error) {
|
||||
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
|
||||
// grab the number of data directory entries
|
||||
var ddLength uint32
|
||||
if pe64 {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader64).NumberOfRvaAndSizes
|
||||
} else {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader32).NumberOfRvaAndSizes
|
||||
}
|
||||
|
||||
// check that the length of data directory entries is large
|
||||
// enough to include the imports directory.
|
||||
if ddLength < IMAGE_DIRECTORY_ENTRY_IMPORT+1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// grab the import data directory entry
|
||||
var idd DataDirectory
|
||||
if pe64 {
|
||||
idd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
} else {
|
||||
idd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
}
|
||||
|
||||
// figure out which section contains the import directory table
|
||||
var ds *Section
|
||||
ds = nil
|
||||
for _, s := range f.Sections {
|
||||
if s.VirtualAddress <= idd.VirtualAddress && idd.VirtualAddress < s.VirtualAddress+s.VirtualSize {
|
||||
ds = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find a section, so no import libraries were found
|
||||
if ds == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sectionData, err := ds.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// seek to the virtual address specified in the import data directory
|
||||
d := sectionData[idd.VirtualAddress-ds.VirtualAddress:]
|
||||
|
||||
// start decoding the import directory
|
||||
var ida []ImportDirectory
|
||||
for len(d) > 0 {
|
||||
var dt ImportDirectory
|
||||
dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
|
||||
dt.TimeDateStamp = binary.LittleEndian.Uint32(d[4:8])
|
||||
dt.ForwarderChain = binary.LittleEndian.Uint32(d[8:12])
|
||||
dt.NameRVA = binary.LittleEndian.Uint32(d[12:16])
|
||||
dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
|
||||
d = d[20:]
|
||||
if dt.OriginalFirstThunk == 0 {
|
||||
break
|
||||
}
|
||||
ida = append(ida, dt)
|
||||
}
|
||||
var all []string
|
||||
for _, dt := range ida {
|
||||
dt.DllName, _ = getString(sectionData, int(dt.NameRVA-ds.VirtualAddress))
|
||||
d = sectionData[:]
|
||||
// seek to OriginalFirstThunk
|
||||
d = d[dt.OriginalFirstThunk-ds.VirtualAddress:]
|
||||
for len(d) > 0 {
|
||||
if pe64 { // 64bit
|
||||
va := binary.LittleEndian.Uint64(d[0:8])
|
||||
d = d[8:]
|
||||
if va == 0 {
|
||||
break
|
||||
}
|
||||
if va&0x8000000000000000 > 0 { // is Ordinal
|
||||
// TODO add dynimport ordinal support.
|
||||
} else {
|
||||
fn, _ := getString(sectionData, int(uint32(va)-ds.VirtualAddress+2))
|
||||
all = append(all, fn+":"+dt.DllName)
|
||||
}
|
||||
} else { // 32bit
|
||||
va := binary.LittleEndian.Uint32(d[0:4])
|
||||
d = d[4:]
|
||||
if va == 0 {
|
||||
break
|
||||
}
|
||||
if va&0x80000000 > 0 { // is Ordinal
|
||||
// TODO add dynimport ordinal support.
|
||||
//ord := va&0x0000FFFF
|
||||
} else {
|
||||
fn, _ := getString(sectionData, int(va-ds.VirtualAddress+2))
|
||||
all = append(all, fn+":"+dt.DllName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the names of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
func (f *File) ImportedLibraries() ([]string, error) {
|
||||
|
||||
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
|
||||
// grab the number of data directory entries
|
||||
var ddLength uint32
|
||||
if pe64 {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader64).NumberOfRvaAndSizes
|
||||
} else {
|
||||
ddLength = f.OptionalHeader.(*OptionalHeader32).NumberOfRvaAndSizes
|
||||
}
|
||||
|
||||
// check that the length of data directory entries is large
|
||||
// enough to include the imports directory.
|
||||
if ddLength < IMAGE_DIRECTORY_ENTRY_IMPORT+1 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// grab the import data directory entry
|
||||
var idd DataDirectory
|
||||
if pe64 {
|
||||
idd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
} else {
|
||||
idd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
|
||||
}
|
||||
|
||||
// figure out which section contains the import directory table
|
||||
var ds *Section
|
||||
ds = nil
|
||||
for _, s := range f.Sections {
|
||||
if s.VirtualAddress <= idd.VirtualAddress && idd.VirtualAddress < s.VirtualAddress+s.VirtualSize {
|
||||
ds = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find a section, so no import libraries were found
|
||||
if ds == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sectionData, err := ds.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// seek to the virtual address specified in the import data directory
|
||||
d := sectionData[idd.VirtualAddress-ds.VirtualAddress:]
|
||||
|
||||
// start decoding the import directory
|
||||
var ida []ImportDirectory
|
||||
for len(d) > 0 {
|
||||
var dt ImportDirectory
|
||||
dt.OriginalFirstThunk = binary.LittleEndian.Uint32(d[0:4])
|
||||
dt.TimeDateStamp = binary.LittleEndian.Uint32(d[4:8])
|
||||
dt.ForwarderChain = binary.LittleEndian.Uint32(d[8:12])
|
||||
dt.NameRVA = binary.LittleEndian.Uint32(d[12:16])
|
||||
dt.FirstThunk = binary.LittleEndian.Uint32(d[16:20])
|
||||
d = d[20:]
|
||||
if dt.OriginalFirstThunk == 0 {
|
||||
break
|
||||
}
|
||||
ida = append(ida, dt)
|
||||
}
|
||||
var all []string
|
||||
for _, dt := range ida {
|
||||
dt.DllName, _ = getString(sectionData, int(dt.NameRVA-ds.VirtualAddress))
|
||||
all = append(all, dt.DllName)
|
||||
}
|
||||
|
||||
return all, nil
|
||||
}
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type IMAGE_COR20_HEADER struct {
|
||||
Cb uint32
|
||||
MajorRuntimeVersion uint16
|
||||
MinorRuntimeVersion uint16
|
||||
MetaDataRVA, MetaDataSize uint32
|
||||
Flags uint32 //todo: define flags
|
||||
EntryPointToken uint32
|
||||
ResourcesRVA, ResourcesSize,
|
||||
StrongNameSignatureRVA, StrongNameSignatureSize,
|
||||
CodeManagerTableRVA, CodeManagerTableSize,
|
||||
VTableFixupsRVA, VTableFixupsSize,
|
||||
ExportAddressTableJumpsRVA, ExportAddressTableJumpsSize,
|
||||
ManagedNativeHeaderRVA, ManagedNativeHeaderSize uint32
|
||||
}
|
||||
|
||||
//Net provides a public interface for getting at some net info.
|
||||
type Net struct {
|
||||
NetDirectory IMAGE_COR20_HEADER //Net directory information
|
||||
MetaData NetMetaData //MetaData Header
|
||||
}
|
||||
|
||||
type NetMetaData struct {
|
||||
Signature [4]byte //should be 0x424a4542
|
||||
MajorVersion uint16
|
||||
MinorVersion uint16
|
||||
Reserved uint32
|
||||
VersionLength uint32
|
||||
VersionString []byte
|
||||
Flags uint16 //todo: define flags betterer
|
||||
NumberOfStreams uint16
|
||||
}
|
||||
|
||||
func newMetadataHeader(i io.Reader) (NetMetaData, error) {
|
||||
r := NetMetaData{}
|
||||
|
||||
//todo: error checks/sanity checks
|
||||
binary.Read(i, binary.LittleEndian, &r.Signature)
|
||||
binary.Read(i, binary.LittleEndian, &r.MajorVersion)
|
||||
binary.Read(i, binary.LittleEndian, &r.MinorVersion)
|
||||
binary.Read(i, binary.LittleEndian, &r.Reserved)
|
||||
|
||||
// it appears that this value is terminated by two nulls.. that might be important at some point
|
||||
binary.Read(i, binary.LittleEndian, &r.VersionLength)
|
||||
r.VersionString = make([]byte, r.VersionLength)
|
||||
i.Read(r.VersionString)
|
||||
|
||||
binary.Read(i, binary.LittleEndian, r.Flags)
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
//NetCLRVersion returns the CLR version specified by the binary. Returns an empty string if not a net binary. String has had trailing nulls stripped.
|
||||
func (f File) NetCLRVersion() string {
|
||||
b := f.Net.MetaData.VersionString
|
||||
for i, x := range b {
|
||||
if x == 0x00 {
|
||||
b = b[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pe
|
||||
|
||||
type DosHeader struct {
|
||||
MZSignature uint16
|
||||
UsedBytesInTheLastPage uint16
|
||||
FileSizeInPages uint16
|
||||
NumberOfRelocationItems uint16
|
||||
HeaderSizeInParagraphs uint16
|
||||
MinimumExtraParagraphs uint16
|
||||
MaximumExtraParagraphs uint16
|
||||
InitialRelativeSS uint16
|
||||
InitialSP uint16
|
||||
CheckSum uint16
|
||||
InitialIP uint16
|
||||
InitialRelativeCS uint16
|
||||
AddressOfRelocationTable uint16
|
||||
OverlayNumber uint16
|
||||
Reserved [4]uint16
|
||||
OEMid uint16
|
||||
OEMinfo uint16
|
||||
Reserved2 [10]uint16
|
||||
AddressOfNewExeHeader uint32
|
||||
}
|
||||
|
||||
type FileHeader struct {
|
||||
Machine uint16
|
||||
NumberOfSections uint16
|
||||
TimeDateStamp uint32
|
||||
PointerToSymbolTable uint32
|
||||
NumberOfSymbols uint32
|
||||
SizeOfOptionalHeader uint16
|
||||
Characteristics uint16
|
||||
}
|
||||
|
||||
type DataDirectory struct {
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type OptionalHeader32 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
BaseOfData uint32
|
||||
ImageBase uint32
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint32
|
||||
SizeOfStackCommit uint32
|
||||
SizeOfHeapReserve uint32
|
||||
SizeOfHeapCommit uint32
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]DataDirectory
|
||||
}
|
||||
|
||||
type OptionalHeader64 struct {
|
||||
Magic uint16
|
||||
MajorLinkerVersion uint8
|
||||
MinorLinkerVersion uint8
|
||||
SizeOfCode uint32
|
||||
SizeOfInitializedData uint32
|
||||
SizeOfUninitializedData uint32
|
||||
AddressOfEntryPoint uint32
|
||||
BaseOfCode uint32
|
||||
ImageBase uint64
|
||||
SectionAlignment uint32
|
||||
FileAlignment uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
MajorImageVersion uint16
|
||||
MinorImageVersion uint16
|
||||
MajorSubsystemVersion uint16
|
||||
MinorSubsystemVersion uint16
|
||||
Win32VersionValue uint32
|
||||
SizeOfImage uint32
|
||||
SizeOfHeaders uint32
|
||||
CheckSum uint32
|
||||
Subsystem uint16
|
||||
DllCharacteristics uint16
|
||||
SizeOfStackReserve uint64
|
||||
SizeOfStackCommit uint64
|
||||
SizeOfHeapReserve uint64
|
||||
SizeOfHeapCommit uint64
|
||||
LoaderFlags uint32
|
||||
NumberOfRvaAndSizes uint32
|
||||
DataDirectory [16]DataDirectory
|
||||
}
|
||||
|
||||
const (
|
||||
IMAGE_FILE_MACHINE_UNKNOWN = 0x0
|
||||
IMAGE_FILE_MACHINE_AM33 = 0x1d3
|
||||
IMAGE_FILE_MACHINE_AMD64 = 0x8664
|
||||
IMAGE_FILE_MACHINE_ARM = 0x1c0
|
||||
IMAGE_FILE_MACHINE_ARMNT = 0x1c4
|
||||
IMAGE_FILE_MACHINE_ARM64 = 0xaa64
|
||||
IMAGE_FILE_MACHINE_EBC = 0xebc
|
||||
IMAGE_FILE_MACHINE_I386 = 0x14c
|
||||
IMAGE_FILE_MACHINE_IA64 = 0x200
|
||||
IMAGE_FILE_MACHINE_M32R = 0x9041
|
||||
IMAGE_FILE_MACHINE_MIPS16 = 0x266
|
||||
IMAGE_FILE_MACHINE_MIPSFPU = 0x366
|
||||
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
|
||||
IMAGE_FILE_MACHINE_POWERPC = 0x1f0
|
||||
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
|
||||
IMAGE_FILE_MACHINE_R4000 = 0x166
|
||||
IMAGE_FILE_MACHINE_SH3 = 0x1a2
|
||||
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
|
||||
IMAGE_FILE_MACHINE_SH4 = 0x1a6
|
||||
IMAGE_FILE_MACHINE_SH5 = 0x1a8
|
||||
IMAGE_FILE_MACHINE_THUMB = 0x1c2
|
||||
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
|
||||
)
|
||||
|
||||
// IMAGE_DIRECTORY_ENTRY constants
|
||||
const (
|
||||
IMAGE_DIRECTORY_ENTRY_EXPORT = 0
|
||||
IMAGE_DIRECTORY_ENTRY_IMPORT = 1
|
||||
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
|
||||
IMAGE_DIRECTORY_ENTRY_SECURITY = 4
|
||||
IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
|
||||
IMAGE_DIRECTORY_ENTRY_DEBUG = 6
|
||||
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7
|
||||
IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
|
||||
IMAGE_DIRECTORY_ENTRY_TLS = 9
|
||||
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
|
||||
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
|
||||
IMAGE_DIRECTORY_ENTRY_IAT = 12
|
||||
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
|
||||
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
|
||||
)
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// RelocationTable - for base relocation entries
|
||||
type RelocationTableEntry struct {
|
||||
RelocationBlock
|
||||
BlockItems []BlockItem
|
||||
}
|
||||
|
||||
// RelocationBlock - for base relocation entries
|
||||
type RelocationBlock struct {
|
||||
VirtualAddress uint32
|
||||
SizeOfBlock uint32
|
||||
}
|
||||
|
||||
// BlockItem - relocation block item
|
||||
type BlockItem struct {
|
||||
Type byte // 4 bits
|
||||
Offset uint16 // 12 bits
|
||||
}
|
||||
|
||||
// Reloc represents a PE COFF relocation.
|
||||
// Each section contains its own relocation list.
|
||||
type Reloc struct {
|
||||
VirtualAddress uint32
|
||||
SymbolTableIndex uint32
|
||||
Type uint16
|
||||
}
|
||||
|
||||
const (
|
||||
//IMAGE_REL_BASED_ABSOLUTE - The base relocation is skipped. This type can be used to pad a block.
|
||||
IMAGE_REL_BASED_ABSOLUTE = 0
|
||||
|
||||
//IMAGE_REL_BASED_HIGH = 1
|
||||
//IMAGE_REL_BASED_LOW = 2
|
||||
|
||||
//IMAGE_REL_BASED_HIGHLOW - The base relocation applies all 32 bits of the difference to the 32-bit field at offset.
|
||||
IMAGE_REL_BASED_HIGHLOW = 3
|
||||
|
||||
//IMAGE_REL_BASED_HIGHADJ = 4
|
||||
//IMAGE_REL_BASED_MIPS_JMPADDR = 5
|
||||
//IMAGE_REL_BASED_ARM_MOV32 = 5
|
||||
//IMAGE_REL_BASED_RISCV_HIGH20 = 5
|
||||
//IMAGE_REL_BASED_THUMB_MOV32 = 7
|
||||
//IMAGE_REL_BASED_RISCV_LOW12I = 7
|
||||
//IMAGE_REL_BASED_RISCV_LOW12S = 8
|
||||
//IMAGE_REL_BASED_MIPS_JMPADDR16 = 9
|
||||
IMAGE_REL_BASED_DIR64 = 10
|
||||
)
|
||||
|
||||
// readBaseRelocationTable - reads the base relocation table from the file and stores it
|
||||
func (f *File) readBaseRelocationTable() (*[]RelocationTableEntry, error) {
|
||||
|
||||
if f.OptionalHeader == nil { // Optional header is optional, might not exist
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var dd DataDirectory
|
||||
if f.Machine == IMAGE_FILE_MACHINE_AMD64 {
|
||||
dd = f.OptionalHeader.(*OptionalHeader64).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
|
||||
} else {
|
||||
dd = f.OptionalHeader.(*OptionalHeader32).DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
|
||||
}
|
||||
var sectionData []byte
|
||||
var err error
|
||||
for _, section := range f.Sections {
|
||||
if section.VirtualAddress == dd.VirtualAddress {
|
||||
sectionData, err = section.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
r := bytes.NewReader(sectionData)
|
||||
var reloBlocks []RelocationTableEntry
|
||||
bytesRead := uint32(0)
|
||||
for bytesRead < dd.Size {
|
||||
var reloBlock RelocationBlock
|
||||
err = binary.Read(r, binary.LittleEndian, &reloBlock)
|
||||
bytesRead += 8
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read relocation block: %v", err)
|
||||
}
|
||||
numBlocks := (reloBlock.SizeOfBlock - 8) / 2
|
||||
blocks := make([]BlockItem, numBlocks)
|
||||
for i := uint32(0); i < numBlocks; i++ {
|
||||
var buf [2]byte
|
||||
err = binary.Read(r, binary.LittleEndian, &buf)
|
||||
bytesRead += 2
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read relocation block item %d: %v", i, err)
|
||||
}
|
||||
var item BlockItem
|
||||
val := binary.LittleEndian.Uint16(buf[:2])
|
||||
item.Type = byte(val >> 12)
|
||||
item.Offset = val & 0x0fff
|
||||
blocks[i] = item
|
||||
}
|
||||
reloBlocks = append(reloBlocks, RelocationTableEntry{reloBlock, blocks})
|
||||
}
|
||||
return &reloBlocks, nil
|
||||
}
|
||||
|
||||
// Relocate - performs base relocations on this image to the given offset
|
||||
func (f *File) Relocate(baseAddr uint64, image *[]byte) {
|
||||
var imageBase uint64
|
||||
pe64 := f.Machine == IMAGE_FILE_MACHINE_AMD64
|
||||
if pe64 {
|
||||
imageBase = f.OptionalHeader.(*OptionalHeader64).ImageBase
|
||||
} else {
|
||||
imageBase = uint64(f.OptionalHeader.(*OptionalHeader32).ImageBase)
|
||||
}
|
||||
for _, block := range *f.BaseRelocationTable {
|
||||
pageRVA := block.VirtualAddress
|
||||
for _, item := range block.BlockItems {
|
||||
if item.Type == IMAGE_REL_BASED_HIGHLOW { // 32 bit
|
||||
delta := uint32(baseAddr - imageBase)
|
||||
fileOffset := f.RVAToFileOffset(pageRVA)
|
||||
idx := fileOffset + uint32(item.Offset)
|
||||
originalAddress := binary.LittleEndian.Uint32((*image)[idx : idx+4])
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, originalAddress+delta)
|
||||
copy((*image)[idx:idx+4], b)
|
||||
} else if item.Type == IMAGE_REL_BASED_DIR64 { // 64 bit
|
||||
delta := baseAddr - imageBase
|
||||
fileOffset := f.RVAToFileOffset(pageRVA)
|
||||
idx := fileOffset + uint32(item.Offset)
|
||||
originalAddress := binary.LittleEndian.Uint64((*image)[idx : idx+8])
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, originalAddress+delta)
|
||||
copy((*image)[idx:idx+8], b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update imageBase in the optional header
|
||||
if pe64 {
|
||||
b := make([]byte, 8)
|
||||
binary.LittleEndian.PutUint64(b, baseAddr)
|
||||
idx := f.OptionalHeaderOffset + 24
|
||||
copy((*image)[idx:idx+8], b)
|
||||
} else {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, uint32(baseAddr))
|
||||
idx := f.OptionalHeaderOffset + 28
|
||||
copy((*image)[idx:idx+4], b)
|
||||
}
|
||||
}
|
||||
|
||||
func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
|
||||
if sh.NumberOfRelocations <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(sh.PointerToRelocations), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
|
||||
}
|
||||
relocs := make([]Reloc, sh.NumberOfRelocations)
|
||||
err = binary.Read(r, binary.LittleEndian, relocs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read section relocations: %v", err)
|
||||
}
|
||||
return relocs, nil
|
||||
}
|
||||
-103
@@ -1,103 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pe
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SectionHeader32 represents real PE COFF section header.
|
||||
type SectionHeader32 struct {
|
||||
Name [8]uint8
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
SizeOfRawData uint32
|
||||
PointerToRawData uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// fullName finds real name of section sh. Normally name is stored
|
||||
// in sh.Name, but if it is longer then 8 characters, it is stored
|
||||
// in COFF string table st instead.
|
||||
func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
|
||||
if sh.Name[0] != '/' {
|
||||
return cstring(sh.Name[:]), nil
|
||||
}
|
||||
i, err := strconv.Atoi(cstring(sh.Name[1:]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return st.String(uint32(i))
|
||||
}
|
||||
|
||||
// SectionHeader is similar to SectionHeader32 with Name
|
||||
// field replaced by Go string. OriginalName is the
|
||||
// original name of the section on disk.
|
||||
type SectionHeader struct {
|
||||
Name string
|
||||
OriginalName [8]uint8
|
||||
VirtualSize uint32
|
||||
VirtualAddress uint32
|
||||
Size uint32
|
||||
Offset uint32
|
||||
PointerToRelocations uint32
|
||||
PointerToLineNumbers uint32
|
||||
NumberOfRelocations uint16
|
||||
NumberOfLineNumbers uint16
|
||||
Characteristics uint32
|
||||
}
|
||||
|
||||
// Section provides access to PE COFF section.
|
||||
type Section struct {
|
||||
SectionHeader
|
||||
Relocs []Reloc
|
||||
|
||||
// Embed ReaderAt for ReadAt method.
|
||||
// Do not embed SectionReader directly
|
||||
// to avoid having Read and Seek.
|
||||
// If a client wants Read and Seek it must use
|
||||
// Open() to avoid fighting over the seek offset
|
||||
// with other clients.
|
||||
io.ReaderAt
|
||||
sr *io.SectionReader
|
||||
}
|
||||
|
||||
// Data reads and returns the contents of the PE section s.
|
||||
func (s *Section) Data() ([]byte, error) {
|
||||
|
||||
if s.sr == nil { // This section was added from code, the internal SectionReader is nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
dat := make([]byte, s.sr.Size())
|
||||
n, err := s.sr.ReadAt(dat, 0)
|
||||
if n == len(dat) {
|
||||
err = nil
|
||||
}
|
||||
return dat[0:n], err
|
||||
}
|
||||
|
||||
// Open returns a new ReadSeeker reading the PE section s.
|
||||
func (s *Section) Open() io.ReadSeeker {
|
||||
return io.NewSectionReader(s.sr, 0, 1<<63-1)
|
||||
}
|
||||
|
||||
// Section Flags (Characteristics field)
|
||||
const (
|
||||
IMAGE_SCN_CNT_CODE = 0x00000020 // Section contains code
|
||||
IMAGE_SCN_MEM_EXECUTE = 0x20000000 // Section is executable
|
||||
IMAGE_SCN_MEM_READ = 0x40000000 // Section is readable
|
||||
|
||||
IMAGE_FILE_RELOCS_STRIPPED = 0x0001 // Relocation info stripped from file
|
||||
|
||||
IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 // Image is NX compatable
|
||||
|
||||
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 // DLL can move
|
||||
)
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// cstring converts ASCII byte sequence b to string.
|
||||
// It stops once it finds 0 or reaches end of b.
|
||||
func cstring(b []byte) string {
|
||||
i := bytes.IndexByte(b, 0)
|
||||
if i == -1 {
|
||||
i = len(b)
|
||||
}
|
||||
return string(b[:i])
|
||||
}
|
||||
|
||||
// StringTable is a COFF string table.
|
||||
type StringTable []byte
|
||||
|
||||
func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) {
|
||||
// COFF string table is located right after COFF symbol table.
|
||||
if fh.PointerToSymbolTable <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
|
||||
_, err := r.Seek(int64(offset), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to string table: %v", err)
|
||||
}
|
||||
var l uint32
|
||||
err = binary.Read(r, binary.LittleEndian, &l)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read string table length: %v", err)
|
||||
}
|
||||
// string table length includes itself
|
||||
if l <= 4 {
|
||||
return nil, nil
|
||||
}
|
||||
l -= 4
|
||||
buf := make([]byte, l)
|
||||
_, err = io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read string table: %v", err)
|
||||
}
|
||||
// re-add the length to the first four bytes of the string table
|
||||
lbuf := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(lbuf, l)
|
||||
|
||||
return StringTable(append(lbuf, buf...)), nil
|
||||
}
|
||||
|
||||
// String extracts string from COFF string table st at offset start.
|
||||
func (st StringTable) String(start uint32) (string, error) {
|
||||
// start includes 4 bytes of string table length
|
||||
if start < 4 {
|
||||
return "", fmt.Errorf("offset %d is before the start of string table", start)
|
||||
}
|
||||
//start -= 4 // we are now including the uint32 length in the StringTable buffer as a prefix, this might change
|
||||
if int(start) > len(st) {
|
||||
return "", fmt.Errorf("offset %d is beyond the end of string table", start)
|
||||
}
|
||||
return cstring(st[start:]), nil
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package pe
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
const COFFSymbolSize = 18
|
||||
|
||||
// COFFSymbol represents single COFF symbol table record.
|
||||
type COFFSymbol struct {
|
||||
Name [8]uint8
|
||||
Value uint32
|
||||
SectionNumber int16
|
||||
Type uint16
|
||||
StorageClass uint8
|
||||
NumberOfAuxSymbols uint8
|
||||
}
|
||||
|
||||
func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
|
||||
if fh.PointerToSymbolTable == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if fh.NumberOfSymbols <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
_, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
|
||||
}
|
||||
syms := make([]COFFSymbol, fh.NumberOfSymbols)
|
||||
err = binary.Read(r, binary.LittleEndian, syms)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fail to read symbol table: %v", err)
|
||||
}
|
||||
return syms, nil
|
||||
}
|
||||
|
||||
// isSymNameOffset checks symbol name if it is encoded as offset into string table.
|
||||
func isSymNameOffset(name [8]byte) (bool, uint32) {
|
||||
if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
|
||||
return true, binary.LittleEndian.Uint32(name[4:])
|
||||
}
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// FullName finds real name of symbol sym. Normally name is stored
|
||||
// in sym.Name, but if it is longer then 8 characters, it is stored
|
||||
// in COFF string table st instead.
|
||||
func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
|
||||
if ok, offset := isSymNameOffset(sym.Name); ok {
|
||||
return st.String(offset)
|
||||
}
|
||||
return cstring(sym.Name[:]), nil
|
||||
}
|
||||
|
||||
func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
|
||||
if len(allsyms) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
syms := make([]*Symbol, 0)
|
||||
aux := uint8(0)
|
||||
for _, sym := range allsyms {
|
||||
if aux > 0 {
|
||||
aux--
|
||||
continue
|
||||
}
|
||||
name, err := sym.FullName(st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aux = sym.NumberOfAuxSymbols
|
||||
s := &Symbol{
|
||||
Name: name,
|
||||
Value: sym.Value,
|
||||
SectionNumber: sym.SectionNumber,
|
||||
Type: sym.Type,
|
||||
StorageClass: sym.StorageClass,
|
||||
}
|
||||
syms = append(syms, s)
|
||||
}
|
||||
return syms, nil
|
||||
}
|
||||
|
||||
// Symbol is similar to COFFSymbol with Name field replaced
|
||||
// by Go string. Symbol also does not have NumberOfAuxSymbols.
|
||||
type Symbol struct {
|
||||
Name string
|
||||
Value uint32
|
||||
SectionNumber int16
|
||||
Type uint16
|
||||
StorageClass uint8
|
||||
}
|
||||
-195
@@ -1,195 +0,0 @@
|
||||
package pe
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
func (peFile *File) Bytes() ([]byte, error) {
|
||||
var bytesWritten uint64
|
||||
peBuf := bytes.NewBuffer(nil)
|
||||
|
||||
// write DOS header and stub
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.DosHeader)
|
||||
bytesWritten += uint64(binary.Size(peFile.DosHeader))
|
||||
if peFile.DosExists {
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.DosStub)
|
||||
bytesWritten += uint64(binary.Size(peFile.DosStub))
|
||||
}
|
||||
|
||||
// write Rich header
|
||||
if peFile.RichHeader != nil {
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.RichHeader)
|
||||
bytesWritten += uint64(len(peFile.RichHeader))
|
||||
}
|
||||
|
||||
// apply padding before PE header if necessary
|
||||
if uint32(bytesWritten) != peFile.DosHeader.AddressOfNewExeHeader {
|
||||
padding := make([]byte, peFile.DosHeader.AddressOfNewExeHeader-uint32(bytesWritten))
|
||||
binary.Write(peBuf, binary.LittleEndian, padding)
|
||||
bytesWritten += uint64(len(padding))
|
||||
}
|
||||
|
||||
// write PE header
|
||||
peMagic := []byte{'P', 'E', 0x00, 0x00}
|
||||
binary.Write(peBuf, binary.LittleEndian, peMagic)
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.FileHeader)
|
||||
bytesWritten += uint64(binary.Size(peFile.FileHeader) + len(peMagic))
|
||||
|
||||
var (
|
||||
is32bit bool
|
||||
oldCertTableOffset, oldCertTableSize uint32
|
||||
)
|
||||
|
||||
switch peFile.FileHeader.Machine {
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
is32bit = true
|
||||
optionalHeader := peFile.OptionalHeader.(*OptionalHeader32)
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.OptionalHeader.(*OptionalHeader32))
|
||||
bytesWritten += uint64(binary.Size(optionalHeader))
|
||||
|
||||
oldCertTableOffset = optionalHeader.DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
||||
oldCertTableSize = optionalHeader.DataDirectory[CERTIFICATE_TABLE].Size
|
||||
case IMAGE_FILE_MACHINE_AMD64:
|
||||
is32bit = false
|
||||
optionalHeader := peFile.OptionalHeader.(*OptionalHeader64)
|
||||
binary.Write(peBuf, binary.LittleEndian, optionalHeader)
|
||||
bytesWritten += uint64(binary.Size(optionalHeader))
|
||||
|
||||
oldCertTableOffset = optionalHeader.DataDirectory[CERTIFICATE_TABLE].VirtualAddress
|
||||
oldCertTableSize = optionalHeader.DataDirectory[CERTIFICATE_TABLE].Size
|
||||
default:
|
||||
return nil, errors.New("architecture not supported")
|
||||
}
|
||||
|
||||
// write section headers
|
||||
sectionHeaders := make([]SectionHeader32, len(peFile.Sections))
|
||||
for idx, section := range peFile.Sections {
|
||||
// write section header
|
||||
sectionHeader := SectionHeader32{
|
||||
Name: section.OriginalName,
|
||||
VirtualSize: section.VirtualSize,
|
||||
VirtualAddress: section.VirtualAddress,
|
||||
SizeOfRawData: section.Size,
|
||||
PointerToRawData: section.Offset,
|
||||
PointerToRelocations: section.PointerToRelocations,
|
||||
PointerToLineNumbers: section.PointerToLineNumbers,
|
||||
NumberOfRelocations: section.NumberOfRelocations,
|
||||
NumberOfLineNumbers: section.NumberOfLineNumbers,
|
||||
Characteristics: section.Characteristics,
|
||||
}
|
||||
|
||||
// if the PE file was pulled from memory, the symbol table offset in the header will be wrong.
|
||||
// Fix it up by picking the section that lines up, and use the raw offset instead.
|
||||
if peFile.FileHeader.PointerToSymbolTable == sectionHeader.VirtualAddress {
|
||||
peFile.FileHeader.PointerToSymbolTable = sectionHeader.PointerToRawData
|
||||
}
|
||||
|
||||
sectionHeaders[idx] = sectionHeader
|
||||
|
||||
//log.Printf("section: %+v\nsectionHeader: %+v\n", section, sectionHeader)
|
||||
|
||||
binary.Write(peBuf, binary.LittleEndian, sectionHeader)
|
||||
bytesWritten += uint64(binary.Size(sectionHeader))
|
||||
}
|
||||
|
||||
// write sections' data
|
||||
for idx, sectionHeader := range sectionHeaders {
|
||||
section := peFile.Sections[idx]
|
||||
sectionData, err := section.Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sectionData == nil { // for sections that weren't in the original file
|
||||
sectionData = []byte{}
|
||||
}
|
||||
if section.Offset != 0 && bytesWritten < uint64(section.Offset) {
|
||||
pad := make([]byte, uint64(section.Offset)-bytesWritten)
|
||||
peBuf.Write(pad)
|
||||
//log.Printf("Padding before section %s at %x: length:%x to:%x\n", section.Name, bytesWritten, len(pad), section.Offset)
|
||||
bytesWritten += uint64(len(pad))
|
||||
}
|
||||
// if our shellcode insertion address is inside this section, insert it at the correct offset in sectionData
|
||||
if peFile.InsertionAddr >= section.Offset && int64(peFile.InsertionAddr) < (int64(section.Offset)+int64(section.Size)-int64(len(peFile.InsertionBytes))) {
|
||||
sectionData = append(sectionData, peFile.InsertionBytes[:]...)
|
||||
datalen := len(sectionData)
|
||||
if sectionHeader.SizeOfRawData > uint32(datalen) {
|
||||
paddingSize := sectionHeader.SizeOfRawData - uint32(datalen)
|
||||
padding := make([]byte, paddingSize, paddingSize)
|
||||
sectionData = append(sectionData, padding...)
|
||||
//log.Printf("Padding after section %s: length:%d\n", section.Name, paddingSize)
|
||||
}
|
||||
}
|
||||
|
||||
binary.Write(peBuf, binary.LittleEndian, sectionData)
|
||||
bytesWritten += uint64(len(sectionData))
|
||||
}
|
||||
|
||||
// write symbols
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.COFFSymbols)
|
||||
bytesWritten += uint64(binary.Size(peFile.COFFSymbols))
|
||||
|
||||
// write the string table
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.StringTable)
|
||||
bytesWritten += uint64(binary.Size(peFile.StringTable))
|
||||
|
||||
var newCertTableOffset, newCertTableSize uint32
|
||||
|
||||
// write the certificate table
|
||||
if peFile.CertificateTable != nil {
|
||||
newCertTableOffset = uint32(bytesWritten)
|
||||
newCertTableSize = uint32(len(peFile.CertificateTable))
|
||||
} else {
|
||||
newCertTableOffset = 0
|
||||
newCertTableSize = 0
|
||||
}
|
||||
|
||||
binary.Write(peBuf, binary.LittleEndian, peFile.CertificateTable)
|
||||
bytesWritten += uint64(len(peFile.CertificateTable))
|
||||
|
||||
peData := peBuf.Bytes()
|
||||
|
||||
// write the offset and size of the new Certificate Table if it changed
|
||||
if newCertTableOffset != oldCertTableOffset || newCertTableSize != oldCertTableSize {
|
||||
certTableInfo := &DataDirectory{
|
||||
VirtualAddress: newCertTableOffset,
|
||||
Size: newCertTableSize,
|
||||
}
|
||||
|
||||
var certTableInfoBuf bytes.Buffer
|
||||
binary.Write(&certTableInfoBuf, binary.LittleEndian, certTableInfo)
|
||||
|
||||
var certTableLoc int64
|
||||
if is32bit {
|
||||
certTableLoc = int64(peFile.DosHeader.AddressOfNewExeHeader) + 24 + 128
|
||||
} else {
|
||||
certTableLoc = int64(peFile.DosHeader.AddressOfNewExeHeader) + 24 + 144
|
||||
}
|
||||
|
||||
peData = append(peData[:certTableLoc], append(certTableInfoBuf.Bytes(), peData[int(certTableLoc)+binary.Size(certTableInfo):]...)...)
|
||||
}
|
||||
|
||||
return peData, nil
|
||||
}
|
||||
|
||||
func (peFile *File) WriteFile(destFile string) error {
|
||||
f, err := os.Create(destFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
peData, err := peFile.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.Write(peData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
-674
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
# The Universal Loader
|
||||
|
||||
This loader provides a unified Go interface for loading shared libraries **from memory** on Windows, OSX, and Linux.
|
||||
|
||||
Also included is a cross-platform `Call()` implementation that lets you call into exported symbols from those libraries without stress.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
*libraryPath* set to `lib.so` for Linux, `lib.dyld` for OSX, or `lib.DLL` for Windows, then:
|
||||
|
||||
```
|
||||
image, err = ioutil.ReadFile(libraryPath)
|
||||
...
|
||||
|
||||
loader, err := universal.NewLoader()
|
||||
...
|
||||
|
||||
library, err := loader.LoadLibrary("main", &image)
|
||||
...
|
||||
|
||||
val, err := library.Call("Runme", 7)
|
||||
...
|
||||
```
|
||||
|
||||
Complete working examples of usage can be found in the examples/ folder in this repo.
|
||||
|
||||
|
||||
### Features and Limitations
|
||||
- OSX backend uses the system loader, so multiple interdependent libraries can be loaded.
|
||||
- OSX backend **automatically adds the underscore prefix for you**, so you can refer to symbols the same way on Linux, Windows, and OSX.
|
||||
- Linux and Windows backends do not use the system loader, so interdependent libraries cannot be loaded.
|
||||
- Linux backend does not use memfd!
|
||||
***I believe this is the first Golang Linux loader that does not use memfd!***
|
||||
|
||||
### Supported Architectures
|
||||
- OSX arm64 M1 Apple Chip (tested)
|
||||
***This is the first loader I've seen, Golang or not, that works on the M1!***
|
||||
- OSX amd64 (tested)
|
||||
- Windows amd64 (tested)
|
||||
- Windows 386 (untested, should work)
|
||||
- Linux amd64 (tested)
|
||||
- Linux 386 (untested, should work)
|
||||
- Other POSIX systems on 386, amd64, or arm64 (untested, should work)
|
||||
|
||||
**If you try this on any untested platforms, whether it works or not, let me know!**
|
||||
-188
@@ -1,188 +0,0 @@
|
||||
package universal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Binject/debug/macho"
|
||||
"github.com/awgh/cppgo/asmcall/cdecl"
|
||||
"github.com/awgh/rawreader"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const MaxUint = ^uint(0)
|
||||
const MaxInt = int(MaxUint >> 1)
|
||||
|
||||
// LoadLibraryImpl - loads a single library to memory, without trying to check or load required imports
|
||||
func LoadLibraryImpl(name string, image *[]byte) (*Library, error) {
|
||||
|
||||
// force input image to be a bundle
|
||||
// this is not the most efficient method, but it does create the abililty to do more fixups down the road,
|
||||
// like if we added universal file support
|
||||
machoFile, err := macho.NewFile(bytes.NewReader(*image))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
machoFile.FileHeader.Type = macho.TypeBundle
|
||||
newImage, err := machoFile.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
image = &newImage
|
||||
|
||||
// Find dyld, loop through all the Mach-O images in memory until we find
|
||||
// one that exports NSCreateObjectFileImageFromMemory and NSLinkModule
|
||||
var execBase uintptr = uintptr(0x0000000001000000)
|
||||
ptr := execBase
|
||||
var createObjectAddr, linkModuleAddr uint64
|
||||
|
||||
for i := 0; i < 10; i++ { // quit after the first ten images
|
||||
ptr, err = findMacho(ptr, 0x1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fmt.Printf("Found image at 0x%08x\n", ptr)
|
||||
rawr := rawreader.New(ptr, MaxInt)
|
||||
machoFile, err := macho.NewFileFromMemory(rawr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exports := machoFile.Exports()
|
||||
|
||||
foundCreateObj := false
|
||||
foundLinkModule := false
|
||||
for _, export := range exports {
|
||||
if export.Name == "_NSCreateObjectFileImageFromMemory" {
|
||||
fmt.Println("found NSCreateObjectFileImageFromMemory")
|
||||
createObjectAddr = export.VirtualAddress
|
||||
foundCreateObj = true
|
||||
}
|
||||
if export.Name == "_NSLinkModule" {
|
||||
fmt.Println("found NSLinkModule")
|
||||
linkModuleAddr = export.VirtualAddress
|
||||
foundLinkModule = true
|
||||
}
|
||||
}
|
||||
if foundCreateObj && foundLinkModule {
|
||||
fmt.Println("Found dyld!")
|
||||
break
|
||||
}
|
||||
ptr = ptr + 0x1000
|
||||
}
|
||||
|
||||
createObjectProc := ptr + uintptr(createObjectAddr)
|
||||
linkModuleProc := ptr + uintptr(linkModuleAddr)
|
||||
|
||||
imageLen := uint64(len(*image))
|
||||
var NSObjectFileImage uintptr
|
||||
_, err = cdecl.Call(createObjectProc,
|
||||
uintptr(unsafe.Pointer(&(*image)[0])), // pointer to image (*char)
|
||||
uintptr(unsafe.Pointer(&imageLen)), // length of image (size_t)
|
||||
uintptr(unsafe.Pointer(&NSObjectFileImage))) // output pointer to struct
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options := uint64(3) // NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_BINDNOW
|
||||
modPtr, err := cdecl.Call(linkModuleProc,
|
||||
uintptr(unsafe.Pointer(NSObjectFileImage)), // file image struct from NSCreateObjectFileImageFromMemory
|
||||
uintptr(unsafe.Pointer(&name)), // image name
|
||||
uintptr(unsafe.Pointer(&options))) // image options flags
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
libPtr, err := findMachoPtr(modPtr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
fmt.Printf("Found image at 0x%08x\n", libPtr)
|
||||
|
||||
// parse the Mach-o we just loaded to get the exports
|
||||
rawr := rawreader.New(libPtr, MaxInt)
|
||||
machoFile, err = macho.NewFileFromMemory(rawr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exports := machoFile.Exports()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lib := Library{
|
||||
BaseAddress: libPtr,
|
||||
Exports: make(map[string]uint64),
|
||||
}
|
||||
for _, x := range exports {
|
||||
lib.Exports[x.Name] = uint64(x.VirtualAddress)
|
||||
}
|
||||
return &lib, nil
|
||||
}
|
||||
|
||||
func isPtrValid(p uintptr) bool {
|
||||
r1, _, err := unix.RawSyscall(unix.SYS_CHMOD, p, 0777, 0)
|
||||
if r1 != 0 && err != 2 {
|
||||
return false
|
||||
}
|
||||
return err == 2
|
||||
}
|
||||
|
||||
func findMacho(addr uintptr, increment uint32) (uintptr, error) {
|
||||
var (
|
||||
base uintptr
|
||||
header uint32
|
||||
err error = fmt.Errorf("could not find macho")
|
||||
)
|
||||
ptr := addr
|
||||
for {
|
||||
if isPtrValid(ptr) {
|
||||
header = *(*uint32)(unsafe.Pointer(ptr))
|
||||
if header == macho.Magic64 {
|
||||
base = ptr
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
ptr += uintptr(increment)
|
||||
}
|
||||
return base, err
|
||||
}
|
||||
|
||||
func findMachoPtr(addr uintptr) (uintptr, error) {
|
||||
var (
|
||||
base uintptr
|
||||
header uint32
|
||||
err error = fmt.Errorf("could not find macho")
|
||||
)
|
||||
idx := addr
|
||||
ptr := uintptr(*(*uint64)(unsafe.Pointer(idx)))
|
||||
for {
|
||||
if isPtrValid(ptr) {
|
||||
header = *(*uint32)(unsafe.Pointer(ptr))
|
||||
if header == macho.Magic64 {
|
||||
base = ptr
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
idx += 8
|
||||
ptr = uintptr(*(*uint64)(unsafe.Pointer(idx)))
|
||||
}
|
||||
return base, err
|
||||
}
|
||||
|
||||
// Call - call a function in a loaded library
|
||||
func (l *Library) Call(functionName string, args ...uintptr) (uintptr, error) {
|
||||
|
||||
if len(functionName) > 0 && functionName[0] != '_' {
|
||||
functionName = "_" + functionName
|
||||
} // OSX has underscore-prefixed exports
|
||||
|
||||
proc, ok := l.FindProc(functionName)
|
||||
if !ok {
|
||||
return 0, errors.New("Call did not find export " + functionName)
|
||||
}
|
||||
val, err := cdecl.Call(proc, args...)
|
||||
return val, err
|
||||
}
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
package universal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/Binject/debug/elf"
|
||||
"github.com/awgh/cppgo/asmcall/cdecl"
|
||||
)
|
||||
|
||||
// LoadLibraryImpl - loads a single library to memory, without trying to check or load required imports
|
||||
func LoadLibraryImpl(name string, image *[]byte) (*Library, error) {
|
||||
elflib, err := elf.NewFile(bytes.NewReader(*image))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if elflib.FileHeader.Type != elf.ET_DYN {
|
||||
return nil, errors.New("Cannot load non-dynamic libraries")
|
||||
}
|
||||
exports, err := elflib.Exports()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pageSize := uint64(unix.Getpagesize())
|
||||
var memSize uint64
|
||||
|
||||
loads := make([]*elf.Prog, 0)
|
||||
for _, p := range elflib.Progs {
|
||||
if p.Type != elf.PT_LOAD || p.Filesz == 0 || p.Memsz == 0 {
|
||||
continue
|
||||
}
|
||||
highest := p.Memsz + p.Vaddr
|
||||
if highest > memSize {
|
||||
memSize = highest
|
||||
}
|
||||
loads = append(loads, p)
|
||||
}
|
||||
if memSize%pageSize != 0 { // round up to page size
|
||||
memSize = ((memSize / pageSize) * pageSize) + pageSize
|
||||
}
|
||||
baseBuf, err := unix.Mmap(-1, 0, int(memSize),
|
||||
unix.PROT_READ|unix.PROT_WRITE|unix.PROT_EXEC, unix.MAP_PRIVATE|unix.MAP_ANON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, p := range loads {
|
||||
copy(baseBuf[p.Vaddr:], (*image)[p.Off:p.Off+p.Filesz])
|
||||
}
|
||||
ex := make(map[string]uint64)
|
||||
for _, x := range exports {
|
||||
ex[x.Name] = x.VirtualAddress
|
||||
}
|
||||
library := Library{
|
||||
BaseAddress: uintptr(unsafe.Pointer(&baseBuf[0])),
|
||||
Exports: ex,
|
||||
}
|
||||
return &library, nil
|
||||
}
|
||||
|
||||
// Call - call a function in a loaded library
|
||||
func (l *Library) Call(functionName string, args ...uintptr) (uintptr, error) {
|
||||
proc, ok := l.FindProc(functionName)
|
||||
if !ok {
|
||||
return 0, errors.New("Call did not find export " + functionName)
|
||||
}
|
||||
val, err := cdecl.Call(proc, args...)
|
||||
return val, err
|
||||
}
|
||||
-205
@@ -1,205 +0,0 @@
|
||||
package universal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"unsafe"
|
||||
|
||||
"github.com/Binject/debug/pe"
|
||||
)
|
||||
|
||||
const (
|
||||
MEM_COMMIT = 0x001000
|
||||
MEM_RESERVE = 0x002000
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS = 0x00000004
|
||||
INFINITE = 0xFFFFFFFF
|
||||
)
|
||||
|
||||
// LoadLibraryImpl - loads a single library to memory, without trying to check or load required imports
|
||||
func LoadLibraryImpl(name string, image *[]byte) (*Library, error) {
|
||||
const PtrSize = 32 << uintptr(^uintptr(0)>>63) // are we on a 32bit or 64bit system?
|
||||
pelib, err := pe.NewFile(bytes.NewReader(*image))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pe64 := pelib.Machine == pe.IMAGE_FILE_MACHINE_AMD64
|
||||
if pe64 && PtrSize != 64 {
|
||||
return nil, errors.New("Cannot load a 64bit DLL from a 32bit process")
|
||||
} else if !pe64 && PtrSize != 32 {
|
||||
return nil, errors.New("Cannot load a 32bit DLL from a 64bit process")
|
||||
}
|
||||
|
||||
var sizeOfImage uint32
|
||||
if pe64 {
|
||||
sizeOfImage = pelib.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage
|
||||
} else {
|
||||
sizeOfImage = pelib.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage
|
||||
}
|
||||
r, err := virtualAlloc(0, sizeOfImage, MEM_RESERVE, syscall.PAGE_READWRITE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dst, err := virtualAlloc(r, sizeOfImage, MEM_COMMIT, syscall.PAGE_EXECUTE_READWRITE)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//perform base relocations
|
||||
pelib.Relocate(uint64(dst), image)
|
||||
|
||||
//write to memory
|
||||
CopySections(pelib, image, dst)
|
||||
|
||||
exports, err := pelib.Exports()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lib := Library{
|
||||
BaseAddress: dst,
|
||||
Exports: make(map[string]uint64),
|
||||
}
|
||||
for _, x := range exports {
|
||||
lib.Exports[x.Name] = uint64(x.VirtualAddress)
|
||||
}
|
||||
|
||||
return &lib, nil
|
||||
}
|
||||
|
||||
// CopySections - writes the sections of a PE image to the given base address in memory
|
||||
func CopySections(pefile *pe.File, image *[]byte, loc uintptr) error {
|
||||
// Copy Headers
|
||||
var sizeOfHeaders uint32
|
||||
if pefile.Machine == pe.IMAGE_FILE_MACHINE_AMD64 {
|
||||
sizeOfHeaders = pefile.OptionalHeader.(*pe.OptionalHeader64).SizeOfHeaders
|
||||
} else {
|
||||
sizeOfHeaders = pefile.OptionalHeader.(*pe.OptionalHeader32).SizeOfHeaders
|
||||
}
|
||||
hbuf := (*[^uint32(0)]byte)(unsafe.Pointer(uintptr(loc)))
|
||||
for index := uint32(0); index < sizeOfHeaders; index++ {
|
||||
hbuf[index] = (*image)[index]
|
||||
}
|
||||
|
||||
// Copy Sections
|
||||
for _, section := range pefile.Sections {
|
||||
//fmt.Println("Writing:", fmt.Sprintf("%s %x %x", section.Name, loc, uint32(loc)+section.VirtualAddress))
|
||||
if section.Size == 0 {
|
||||
continue
|
||||
}
|
||||
d, err := section.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dataLen := uint32(len(d))
|
||||
dst := uint64(loc) + uint64(section.VirtualAddress)
|
||||
buf := (*[^uint32(0)]byte)(unsafe.Pointer(uintptr(dst)))
|
||||
for index := uint32(0); index < dataLen; index++ {
|
||||
buf[index] = d[index]
|
||||
}
|
||||
}
|
||||
|
||||
// Write symbol and string tables
|
||||
bbuf := bytes.NewBuffer(nil)
|
||||
binary.Write(bbuf, binary.LittleEndian, pefile.COFFSymbols)
|
||||
binary.Write(bbuf, binary.LittleEndian, pefile.StringTable)
|
||||
b := bbuf.Bytes()
|
||||
blen := uint32(len(b))
|
||||
for index := uint32(0); index < blen; index++ {
|
||||
hbuf[index+pefile.FileHeader.PointerToSymbolTable] = b[index]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
kernel32 = syscall.MustLoadDLL("kernel32.dll")
|
||||
procVirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
|
||||
)
|
||||
|
||||
func virtualAlloc(addr uintptr, size, allocType, protect uint32) (uintptr, error) {
|
||||
r1, _, e1 := procVirtualAlloc.Call(
|
||||
addr,
|
||||
uintptr(size),
|
||||
uintptr(allocType),
|
||||
uintptr(protect))
|
||||
|
||||
if int(r1) == 0 {
|
||||
return r1, os.NewSyscallError("VirtualAlloc", e1)
|
||||
}
|
||||
return r1, nil
|
||||
}
|
||||
|
||||
// Call - call a function in a loaded library
|
||||
//
|
||||
// cribbed from: https://golang.org/src/Syscall/dll_windows.go
|
||||
//
|
||||
// On amd64, Call can pass and return floating-point values. To pass
|
||||
// an argument x with C type "float", use
|
||||
// uintptr(math.Float32bits(x)). To pass an argument with C type
|
||||
// "double", use uintptr(math.Float64bits(x)). Floating-point return
|
||||
// values are returned in r2. The return value for C type "float" is
|
||||
// math.Float32frombits(uint32(r2)). For C type "double", it is
|
||||
// math.Float64frombits(uint64(r2)).
|
||||
func (l *Library) Call(functionName string, args ...uintptr) (uintptr, error) {
|
||||
|
||||
proc, ok := l.FindProc(functionName)
|
||||
if !ok {
|
||||
return 0, errors.New("Call did not find export " + functionName)
|
||||
}
|
||||
var r uintptr
|
||||
var errno syscall.Errno
|
||||
var err error
|
||||
switch len(args) {
|
||||
case 0:
|
||||
r, _, errno = syscall.Syscall(proc, uintptr(len(args)), 0, 0, 0)
|
||||
case 1:
|
||||
r, _, errno = syscall.Syscall(proc, uintptr(len(args)), args[0], 0, 0)
|
||||
case 2:
|
||||
r, _, errno = syscall.Syscall(proc, uintptr(len(args)), args[0], args[1], 0)
|
||||
case 3:
|
||||
r, _, errno = syscall.Syscall(proc, uintptr(len(args)), args[0], args[1], args[2])
|
||||
case 4:
|
||||
r, _, errno = syscall.Syscall6(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], 0, 0)
|
||||
case 5:
|
||||
r, _, errno = syscall.Syscall6(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], 0)
|
||||
case 6:
|
||||
r, _, errno = syscall.Syscall6(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5])
|
||||
case 7:
|
||||
r, _, errno = syscall.Syscall9(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], 0, 0)
|
||||
case 8:
|
||||
r, _, errno = syscall.Syscall9(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], 0)
|
||||
case 9:
|
||||
r, _, errno = syscall.Syscall9(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])
|
||||
case 10:
|
||||
r, _, errno = syscall.Syscall12(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], 0, 0)
|
||||
case 11:
|
||||
r, _, errno = syscall.Syscall12(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], 0)
|
||||
case 12:
|
||||
r, _, errno = syscall.Syscall12(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11])
|
||||
case 13:
|
||||
r, _, errno = syscall.Syscall15(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], 0, 0)
|
||||
case 14:
|
||||
r, _, errno = syscall.Syscall15(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], 0)
|
||||
case 15:
|
||||
r, _, errno = syscall.Syscall15(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14])
|
||||
case 16:
|
||||
r, _, errno = syscall.Syscall18(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], 0, 0)
|
||||
case 17:
|
||||
r, _, errno = syscall.Syscall18(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], 0)
|
||||
case 18:
|
||||
r, _, errno = syscall.Syscall18(proc, uintptr(len(args)), args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17])
|
||||
default:
|
||||
return 0, errors.New("Call " + functionName + " with too many arguments " + strconv.Itoa(len(args)) + ".")
|
||||
}
|
||||
if errno != 0 {
|
||||
errString := errno.Error()
|
||||
if errString != "" {
|
||||
err = errors.New(errString)
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package universal
|
||||
|
||||
// Library - describes a loaded library
|
||||
type Library struct {
|
||||
Name string
|
||||
BaseAddress uintptr
|
||||
Exports map[string]uint64
|
||||
}
|
||||
|
||||
// Loader - keeps track of
|
||||
type Loader struct {
|
||||
Libraries []*Library
|
||||
}
|
||||
|
||||
// NewLoader - returns a new instance of a Loader
|
||||
func NewLoader() (*Loader, error) {
|
||||
return &Loader{}, nil
|
||||
}
|
||||
|
||||
// LoadLibrary - loads a library into this process from the given buffer
|
||||
func (l *Loader) LoadLibrary(name string, image *[]byte) (*Library, error) {
|
||||
|
||||
library, err := LoadLibraryImpl(name, image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
library.Name = name
|
||||
l.Libraries = append(l.Libraries, library)
|
||||
return library, nil
|
||||
}
|
||||
|
||||
// FindProc - returns the address of the given function from the given library
|
||||
func (l *Loader) FindProc(libname string, funcname string) (uintptr, bool) {
|
||||
|
||||
for _, lib := range l.Libraries {
|
||||
if lib.Name == libname {
|
||||
return lib.FindProc(funcname)
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// FindProc - returns the address of the given function in this library
|
||||
func (l *Library) FindProc(funcname string) (uintptr, bool) {
|
||||
v, ok := l.Exports[funcname]
|
||||
return l.BaseAddress + uintptr(v), ok
|
||||
}
|
||||
+10
-21
@@ -1,7 +1,6 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
// Package clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
|
||||
// go-clr is a PoC package that wraps Windows syscalls necessary to load and the CLR into the current process and
|
||||
// execute a managed DLL from disk or a managed EXE from memory
|
||||
package clr
|
||||
|
||||
@@ -12,7 +11,7 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// GetInstalledRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
|
||||
// GetInstallRuntimes is a wrapper function that returns an array of installed runtimes. Requires an existing ICLRMetaHost
|
||||
func GetInstalledRuntimes(metahost *ICLRMetaHost) ([]string, error) {
|
||||
var runtimes []string
|
||||
enumICLRRuntimeInfo, err := metahost.EnumerateInstalledRuntimes()
|
||||
@@ -90,26 +89,16 @@ func ExecuteDLLFromDisk(targetRuntime, dllpath, typeName, methodName, argument s
|
||||
}
|
||||
|
||||
pDLLPath, err := syscall.UTF16PtrFromString(dllpath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
must(err)
|
||||
pTypeName, err := syscall.UTF16PtrFromString(typeName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
must(err)
|
||||
pMethodName, err := syscall.UTF16PtrFromString(methodName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
must(err)
|
||||
pArgument, err := syscall.UTF16PtrFromString(argument)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
must(err)
|
||||
|
||||
ret, err := runtimeHost.ExecuteInDefaultAppDomain(pDLLPath, pTypeName, pMethodName, pArgument)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
must(err)
|
||||
if *ret != 0 {
|
||||
return int16(*ret), fmt.Errorf("the ICLRRuntimeHost::ExecuteInDefaultAppDomain method returned a non-zero return value: %d", *ret)
|
||||
}
|
||||
@@ -211,7 +200,7 @@ func ExecuteByteArray(targetRuntime string, rawBytes []byte, params []string) (r
|
||||
|
||||
// LoadCLR loads the target runtime into the current process and returns the runtimehost
|
||||
// The intended purpose is for the runtimehost to be reused for subsequent operations
|
||||
// throughout the duration of the program. Commonly used with C2 frameworks
|
||||
// throught the duration of the program. Commonly used with C2 frameworks
|
||||
func LoadCLR(targetRuntime string) (runtimeHost *ICORRuntimeHost, err error) {
|
||||
if targetRuntime == "" {
|
||||
targetRuntime = "v4"
|
||||
@@ -311,7 +300,7 @@ func ExecuteByteArrayDefaultDomain(runtimeHost *ICORRuntimeHost, rawBytes []byte
|
||||
|
||||
// LoadAssembly uses a previously instantiated runtimehost and loads an assembly into the default AppDomain
|
||||
// and returns the assembly's methodInfo structure. The intended purpose is for the assembly to be loaded
|
||||
// once but executed many times throughout the duration of the program. Commonly used with C2 frameworks
|
||||
// once but executed many times throught the duration of the program. Commonly used with C2 frameworks
|
||||
func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *MethodInfo, err error) {
|
||||
appDomain, err := GetAppDomain(runtimeHost)
|
||||
if err != nil {
|
||||
@@ -330,7 +319,7 @@ func LoadAssembly(runtimeHost *ICORRuntimeHost, rawBytes []byte) (methodInfo *Me
|
||||
}
|
||||
|
||||
// InvokeAssembly uses the MethodInfo structure of a previously loaded assembly and executes it.
|
||||
// The intended purpose is for the assembly to be executed many times throughout the duration of the
|
||||
// The intended purpose is for the assembly to be executed many times throught the duration of the
|
||||
// program. Commonly used with C2 frameworks
|
||||
func InvokeAssembly(methodInfo *MethodInfo, params []string) (stdout string, stderr string) {
|
||||
var paramSafeArray *SafeArray
|
||||
|
||||
+2
-32
@@ -1,4 +1,3 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package clr
|
||||
@@ -9,7 +8,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@@ -60,41 +58,13 @@ func RedirectStdoutStderr() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new reader and writer for STDERR
|
||||
// Createa new reader and writer for STDERR
|
||||
rSTDERR, wSTDERR, err = os.Pipe()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("there was an error calling the os.Pipe() function to create a new STDERR:\n%s", err)
|
||||
return
|
||||
}
|
||||
|
||||
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
||||
getConsoleWindow := kernel32.NewProc("GetConsoleWindow")
|
||||
|
||||
// Ensure the process has a console because if it doesn't there will be no output to capture
|
||||
hConsole, _, _ := getConsoleWindow.Call()
|
||||
if hConsole == 0 {
|
||||
// https://learn.microsoft.com/en-us/windows/console/allocconsole
|
||||
allocConsole := kernel32.NewProc("AllocConsole")
|
||||
// BOOL WINAPI AllocConsole(void);
|
||||
ret, _, err := allocConsole.Call()
|
||||
// A process can be associated with only one console, so the AllocConsole function fails if the calling process
|
||||
// already has a console. So long as any console exists we are good to go and therefore don't care about errors
|
||||
if ret == 0 {
|
||||
return fmt.Errorf("there was an error calling kernel32!AllocConsole with return code %d: %s", ret, err)
|
||||
}
|
||||
|
||||
// Get a handle to the newly created/allocated console
|
||||
hConsole, _, _ = getConsoleWindow.Call()
|
||||
|
||||
user32 := windows.NewLazySystemDLL("user32.dll")
|
||||
showWindow := user32.NewProc("ShowWindow")
|
||||
// Hide the console window
|
||||
ret, _, err = showWindow.Call(hConsole, windows.SW_HIDE)
|
||||
if err != syscall.Errno(0) {
|
||||
return fmt.Errorf("there was an error calling user32!ShowWindow with return %+v: %s", ret, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Set STDOUT/STDERR to the new files from os.Pipe()
|
||||
// https://docs.microsoft.com/en-us/windows/console/setstdhandle
|
||||
if err = windows.SetStdHandle(windows.STD_OUTPUT_HANDLE, windows.Handle(wSTDOUT.Fd())); err != nil {
|
||||
@@ -162,7 +132,7 @@ func ReadStdoutStderr() (stdout string, stderr string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// CloseStdoutStderr closes the Reader/Writer for the previously redirected STDOUT/STDERR
|
||||
// CloseSTdoutStderr closes the Reader/Writer for the prviously redirected STDOUT/STDERR
|
||||
// that was changed to an *os.File
|
||||
func CloseStdoutStderr() (err error) {
|
||||
err = rSTDOUT.Close()
|
||||
|
||||
+8
@@ -5,6 +5,7 @@ package clr
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
@@ -24,6 +25,13 @@ func checkOK(hr uintptr, caller string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// must forces the program to exit if there is an error using the log.Fatal command
|
||||
func must(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func utf16Le(s string) []byte {
|
||||
enc := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
var buf bytes.Buffer
|
||||
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2017 Loren Segal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
// Package cdecl implements method call ABI for the POSIX C/C++ calling
|
||||
// convention.
|
||||
//
|
||||
// Note that this package does not rely on cgo to implement calling, so a
|
||||
// compiler is not needed to call into C functions using this library.
|
||||
package cdecl
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Call calls a cdecl style function at memory address addr with the arguments
|
||||
// list a. The function result value is returned as a uintptr to be translated
|
||||
// by the caller. If the function cannot be called (usually due to an invalid
|
||||
// number of argument), an error is returned.
|
||||
func Call(addr uintptr, a ...uintptr) (uintptr, error) {
|
||||
switch l := len(a); l {
|
||||
case 0:
|
||||
return call0(addr), nil
|
||||
case 1:
|
||||
return call1(addr, a[0]), nil
|
||||
case 2:
|
||||
return call2(addr, a[0], a[1]), nil
|
||||
case 3:
|
||||
return call3(addr, a[0], a[1], a[2]), nil
|
||||
case 4:
|
||||
return call4(addr, a[0], a[1], a[2], a[3]), nil
|
||||
case 5:
|
||||
return call5(addr, a[0], a[1], a[2], a[3], a[4]), nil
|
||||
case 6:
|
||||
return call6(addr, a[0], a[1], a[2], a[3], a[4], a[5]), nil
|
||||
default:
|
||||
return 0, errors.New("too many arguments")
|
||||
}
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
TEXT ·call0(SB),4,$0-8
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+4(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call1(SB),4,$4-12
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call2(SB),4,$8-16
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL b+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+12(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call3(SB),4,$12-20
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL b+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
MOVL c+12(FP), BX
|
||||
MOVL BX, 8(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call4(SB),4,$16-24
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL b+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
MOVL c+12(FP), BX
|
||||
MOVL BX, 8(SP)
|
||||
MOVL d+16(FP), BX
|
||||
MOVL BX, 12(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+20(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call5(SB),4,$20-28
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL b+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
MOVL c+12(FP), BX
|
||||
MOVL BX, 8(SP)
|
||||
MOVL d+16(FP), BX
|
||||
MOVL BX, 12(SP)
|
||||
MOVL e+20(FP), BX
|
||||
MOVL BX, 16(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call6(SB),4,$24-32
|
||||
MOVL a+4(FP), BX
|
||||
MOVL BX, 0(SP)
|
||||
MOVL b+8(FP), BX
|
||||
MOVL BX, 4(SP)
|
||||
MOVL c+12(FP), BX
|
||||
MOVL BX, 8(SP)
|
||||
MOVL d+16(FP), BX
|
||||
MOVL BX, 12(SP)
|
||||
MOVL e+20(FP), BX
|
||||
MOVL BX, 16(SP)
|
||||
MOVL f+24(FP), BX
|
||||
MOVL BX, 20(SP)
|
||||
|
||||
MOVL addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVL AX, ret+28(FP)
|
||||
RET
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package cdecl
|
||||
|
||||
func call0(addr uintptr) uintptr
|
||||
func call1(addr uintptr, a uintptr) uintptr
|
||||
func call2(addr uintptr, a uintptr, b uintptr) uintptr
|
||||
func call3(addr uintptr, a uintptr, b uintptr, c uintptr) uintptr
|
||||
func call4(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr) uintptr
|
||||
func call5(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr) uintptr
|
||||
func call6(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr, f uintptr) uintptr
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
TEXT ·call0(SB),4,$0-16
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call1(SB),4,$0-24
|
||||
MOVQ a+8(FP), DI
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call2(SB),4,$0-32
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call3(SB),4,$0-40
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
MOVQ c+24(FP), DX
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+32(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call4(SB),4,$0-48
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
MOVQ c+24(FP), DX
|
||||
MOVQ d+32(FP), CX
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+40(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call5(SB),4,$0-56
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
MOVQ c+24(FP), DX
|
||||
MOVQ d+32(FP), CX
|
||||
MOVQ e+40(FP), R8
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+48(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call6(SB),4,$0-64
|
||||
MOVQ a+8(FP), DI
|
||||
MOVQ b+16(FP), SI
|
||||
MOVQ c+24(FP), DX
|
||||
MOVQ d+32(FP), CX
|
||||
MOVQ e+40(FP), R8
|
||||
MOVQ f+48(FP), R9
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+56(FP)
|
||||
RET
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
TEXT ·call0(SB),4,$16-8
|
||||
MOVD addr+0(FP), R0
|
||||
CALL R0
|
||||
MOVD R0, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call1(SB),4,$24-16
|
||||
MOVD addr+0(FP), R1
|
||||
MOVD arg1+8(FP), R0
|
||||
CALL R1
|
||||
MOVD R0, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call2(SB),4,$32-24
|
||||
MOVD addr+0(FP), R2
|
||||
MOVD arg1+8(FP), R0
|
||||
MOVD arg2+16(FP), R1
|
||||
CALL R2
|
||||
MOVD R0, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call3(SB),4,$40-32
|
||||
MOVD addr+0(FP), R3
|
||||
MOVD arg1+8(FP), R0
|
||||
MOVD arg2+16(FP), R1
|
||||
MOVD arg3+24(FP), R2
|
||||
CALL R3
|
||||
MOVD R0, ret+32(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call4(SB),4,$48-40
|
||||
MOVD addr+0(FP), R4
|
||||
MOVD arg1+8(FP), R0
|
||||
MOVD arg2+16(FP), R1
|
||||
MOVD arg3+24(FP), R2
|
||||
MOVD arg4+32(FP), R3
|
||||
CALL R4
|
||||
MOVD R0, ret+40(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call5(SB),4,$56-48
|
||||
MOVD addr+0(FP), R5
|
||||
MOVD arg1+8(FP), R0
|
||||
MOVD arg2+16(FP), R1
|
||||
MOVD arg3+24(FP), R2
|
||||
MOVD arg4+32(FP), R3
|
||||
MOVD arg5+40(FP), R4
|
||||
CALL R5
|
||||
MOVD R0, ret+48(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call6(SB),4,$64-56
|
||||
MOVD addr+0(FP), R6
|
||||
MOVD arg1+8(FP), R0
|
||||
MOVD arg2+16(FP), R1
|
||||
MOVD arg3+24(FP), R2
|
||||
MOVD arg4+32(FP), R3
|
||||
MOVD arg5+40(FP), R4
|
||||
MOVD arg6+48(FP), R5
|
||||
CALL R6
|
||||
MOVD R0, ret+56(FP)
|
||||
RET
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package cdecl
|
||||
|
||||
func call0(addr uintptr) uintptr
|
||||
func call1(addr uintptr, a uintptr) uintptr
|
||||
func call2(addr uintptr, a uintptr, b uintptr) uintptr
|
||||
func call3(addr uintptr, a uintptr, b uintptr, c uintptr) uintptr
|
||||
func call4(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr) uintptr
|
||||
func call5(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr) uintptr
|
||||
func call6(addr uintptr, a uintptr, b uintptr, c uintptr, d uintptr, e uintptr, f uintptr) uintptr
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
// +build windows
|
||||
|
||||
TEXT ·call0(SB),4,$32-16
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+8(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call1(SB),0,$32-24
|
||||
MOVQ a+8(FP), CX
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+16(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call2(SB),0,$32-32
|
||||
MOVQ a+8(FP), CX
|
||||
MOVQ b+16(FP), DX
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+24(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call3(SB),0,$32-40
|
||||
MOVQ a+8(FP), CX
|
||||
MOVQ b+16(FP), DX
|
||||
MOVQ c+24(FP), R8
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+32(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call4(SB),0,$32-48
|
||||
MOVQ a+8(FP), CX
|
||||
MOVQ b+16(FP), DX
|
||||
MOVQ c+24(FP), R8
|
||||
MOVQ d+32(FP), R9
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+40(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call5(SB),0,$40-56
|
||||
MOVQ a+8(FP), CX
|
||||
MOVQ b+16(FP), DX
|
||||
MOVQ c+24(FP), R8
|
||||
MOVQ d+32(FP), R9
|
||||
MOVQ e+40(FP), BX
|
||||
MOVQ BX, e-8(SP)
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+48(FP)
|
||||
RET
|
||||
|
||||
TEXT ·call6(SB),0,$48-64
|
||||
MOVQ a+8(FP), CX
|
||||
MOVQ b+16(FP), DX
|
||||
MOVQ c+24(FP), R8
|
||||
MOVQ d+32(FP), R9
|
||||
MOVQ e+40(FP), BX
|
||||
MOVQ BX, e-16(SP)
|
||||
MOVQ f+48(FP), BX
|
||||
MOVQ BX, f-8(SP)
|
||||
|
||||
MOVQ addr+0(FP), AX
|
||||
CALL AX
|
||||
MOVQ AX, ret+56(FP)
|
||||
RET
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 awgh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
# rawreader
|
||||
Implements io.ReaderAt over raw memory.
|
||||
|
||||
You should REFLECT on how UNSAFE this is.
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
package rawreader
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// RawReader implements interfaces implemented by files over raw memory
|
||||
// this is completely unsafe by design
|
||||
// you should either know why you want this exactly or stay away!
|
||||
type RawReader struct {
|
||||
sliceHeader *reflect.SliceHeader
|
||||
rawPtr uintptr
|
||||
Data []byte
|
||||
Length int
|
||||
}
|
||||
|
||||
// New returns a new populated RawReader
|
||||
func New(start uintptr, length int) *RawReader {
|
||||
sh := &reflect.SliceHeader{
|
||||
Data: start,
|
||||
Len: length,
|
||||
Cap: length,
|
||||
}
|
||||
data := *(*[]byte)(unsafe.Pointer(sh))
|
||||
return &RawReader{sliceHeader: sh, rawPtr: start, Data: data, Length: length}
|
||||
}
|
||||
|
||||
// ReadAt implements io.ReaderAt https://golang.org/pkg/io/#ReaderAt
|
||||
// ReadAt reads len(p) bytes into p starting at offset off in the underlying input source.
|
||||
// It returns the number of bytes read (0 <= n <= len(p)) and any error encountered.
|
||||
//
|
||||
// When ReadAt returns n < len(p), it returns a non-nil error explaining why more bytes were not returned.
|
||||
// In this respect, ReadAt is stricter than Read.
|
||||
//
|
||||
// Even if ReadAt returns n < len(p), it may use all of p as scratch space during the call.
|
||||
// If some data is available but not len(p) bytes, ReadAt blocks until either all the data is available or an error occurs.
|
||||
// In this respect ReadAt is different from Read.
|
||||
//
|
||||
// If the n = len(p) bytes returned by ReadAt are at the end of the input source,
|
||||
// ReadAt may return either err == EOF or err == nil.
|
||||
//
|
||||
// If ReadAt is reading from an input source with a seek offset,
|
||||
// ReadAt should not affect nor be affected by the underlying seek offset.
|
||||
// Clients of ReadAt can execute parallel ReadAt calls on the same input source.
|
||||
func (f *RawReader) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, errors.New("RawReader.ReadAt: negative offset")
|
||||
}
|
||||
reqLen := len(p)
|
||||
buffLen := int64(f.Length)
|
||||
if off >= buffLen {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n = copy(p, f.Data[off:])
|
||||
if n < reqLen {
|
||||
err = io.EOF
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
*~
|
||||
Generated
Vendored
+2
-2
@@ -178,7 +178,7 @@
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
@@ -186,7 +186,7 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020-2021 wazero authors
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
# purego
|
||||
[](https://pkg.go.dev/github.com/ebitengine/purego?GOOS=darwin)
|
||||
|
||||
A library for calling C functions from Go without Cgo.
|
||||
|
||||
## Motivation
|
||||
|
||||
The [Ebitengine](https://github.com/hajimehoshi/ebiten) game engine was ported to use only Go on Windows. This enabled
|
||||
cross-compiling to Windows from any other operating system simply by setting `GOOS=windows`. The purego project was
|
||||
born to bring that same vision to the other platforms supported by Ebitengine.
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Simple Cross-Compilation**: No C means you can build for other platforms easily without a C compiler.
|
||||
- **Faster Compilation**: Efficiently cache your entirely Go builds.
|
||||
- **Smaller Binaries**: Using Cgo generates a C wrapper function for each C function called. Purego doesn't!
|
||||
- **Dynamic Linking**: Load symbols at runtime and use it as a plugin system.
|
||||
- **Foreign Function Interface**: Call into other languages that are compiled into shared objects.
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
func getSystemLibrary() string {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return "/usr/lib/libSystem.B.dylib"
|
||||
case "linux":
|
||||
return "libc.so.6"
|
||||
default:
|
||||
panic(fmt.Errorf("GOOS=%s is not supported", runtime.GOOS))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
libc := purego.Dlopen(getSystemLibrary(), purego.RTLD_NOW|purego.RTLD_GLOBAL)
|
||||
if err := purego.Dlerror(); err != "" {
|
||||
panic(err)
|
||||
}
|
||||
var puts func(string)
|
||||
purego.RegisterLibFunc(&puts, libc, "puts")
|
||||
puts("Calling C from Go without Cgo!")
|
||||
}
|
||||
```
|
||||
|
||||
Then to run: `CGO_ENABLED=0 go run main.go`
|
||||
|
||||
### External Code
|
||||
|
||||
Purego uses code that originates from the Go runtime. These files are under the BSD-3
|
||||
License that can be found [in the Go Source](https://github.com/golang/go/blob/master/LICENSE).
|
||||
This is a list of the copied files:
|
||||
|
||||
* `zcallback_darwin_*.s` from package `runtime`
|
||||
* `internal/abi/abi_*.h` from package `runtime/cgo`
|
||||
* `internal/fakecgo/asm_GOARCH.s` from package `runtime/cgo`
|
||||
* `internal/fakecgo/callbacks.go` from package `runtime/cgo`
|
||||
* `internal/fakecgo/go_GOOS_GOARCH.go` from package `runtime/cgo`
|
||||
* `internal/fakecgo/iscgo.go` from package `runtime/cgo`
|
||||
* `internal/fakecgo/setenv.go` from package `runtime/cgo`
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build cgo && (darwin || linux)
|
||||
|
||||
package purego
|
||||
|
||||
// if CGO_ENABLED=1 import the Cgo runtime to ensure that it is set up properly.
|
||||
// This is required since some frameworks need TLS setup the C way which Go doesn't do.
|
||||
// We currently don't support ios in fakecgo mode so force Cgo or fail
|
||||
// Even if CGO_ENABLED=1 the Cgo runtime is not imported unless `import "C"` is used.
|
||||
// which will import this package automatically. Normally this isn't an issue since it
|
||||
// usually isn't possible to call into C without using that import. However, with purego
|
||||
// it is since we don't use `import "C"`!
|
||||
import _ "runtime/cgo"
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build darwin || linux
|
||||
|
||||
package purego
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Unix Specification for dlfcn.h: https://pubs.opengroup.org/onlinepubs/7908799/xsh/dlfcn.h.html
|
||||
|
||||
var (
|
||||
fnDlopen func(path string, mode int) uintptr
|
||||
fnDlsym func(handle uintptr, name string) uintptr
|
||||
fnDlerror func() string
|
||||
fnDlclose func(handle uintptr) bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterFunc(&fnDlopen, dlopenABI0)
|
||||
RegisterFunc(&fnDlsym, dlsymABI0)
|
||||
RegisterFunc(&fnDlerror, dlerrorABI0)
|
||||
RegisterFunc(&fnDlclose, dlcloseABI0)
|
||||
}
|
||||
|
||||
// Dlopen examines the dynamic library or bundle file specified by path. If the file is compatible
|
||||
// with the current process and has not already been loaded into the
|
||||
// current process, it is loaded and linked. After being linked, if it contains
|
||||
// any initializer functions, they are called, before Dlopen
|
||||
// returns. It returns a handle that can be used with Dlsym and Dlclose.
|
||||
// A second call to Dlopen with the same path will return the same handle, but the internal
|
||||
// reference count for the handle will be incremented. Therefore, all
|
||||
// Dlopen calls should be balanced with a Dlclose call.
|
||||
func Dlopen(path string, mode int) uintptr {
|
||||
return fnDlopen(path, mode)
|
||||
}
|
||||
|
||||
// Dlsym takes a "handle" of a dynamic library returned by Dlopen and the symbol name.
|
||||
// It returns the address where that symbol is loaded into memory. If the symbol is not found,
|
||||
// in the specified library or any of the libraries that were automatically loaded by Dlopen
|
||||
// when that library was loaded, Dlsym returns zero.
|
||||
func Dlsym(handle uintptr, name string) uintptr {
|
||||
return fnDlsym(handle, name)
|
||||
}
|
||||
|
||||
// Dlerror returns a human-readable string describing the most recent error that
|
||||
// occurred from Dlopen, Dlsym or Dlclose since the last call to Dlerror. It
|
||||
// returns an empty string if no errors have occurred since initialization or
|
||||
// since it was last called.
|
||||
func Dlerror() string {
|
||||
// msg is only valid until the next call to Dlerror
|
||||
// which is why it gets copied into a Go string
|
||||
return fnDlerror()
|
||||
}
|
||||
|
||||
// Dlclose decrements the reference count on the dynamic library handle.
|
||||
// If the reference count drops to zero and no other loaded libraries
|
||||
// use symbols in it, then the dynamic library is unloaded.
|
||||
// Dlclose returns false on success, and true on error.
|
||||
func Dlclose(handle uintptr) bool {
|
||||
return fnDlclose(handle)
|
||||
}
|
||||
|
||||
// these functions exist in dlfcn_stubs.s and are calling C functions linked to in dlfcn_GOOS.go
|
||||
// the indirection is necessary because a function is actually a pointer to the pointer to the code.
|
||||
// sadly, I do not know of anyway to remove the assembly stubs entirely because //go:linkname doesn't
|
||||
// appear to work if you link directly to the C function on darwin arm64.
|
||||
|
||||
//go:linkname dlopen dlopen
|
||||
var dlopen uintptr
|
||||
var dlopenABI0 = uintptr(unsafe.Pointer(&dlopen))
|
||||
|
||||
//go:linkname dlsym dlsym
|
||||
var dlsym uintptr
|
||||
var dlsymABI0 = uintptr(unsafe.Pointer(&dlsym))
|
||||
|
||||
//go:linkname dlclose dlclose
|
||||
var dlclose uintptr
|
||||
var dlcloseABI0 = uintptr(unsafe.Pointer(&dlclose))
|
||||
|
||||
//go:linkname dlerror dlerror
|
||||
var dlerror uintptr
|
||||
var dlerrorABI0 = uintptr(unsafe.Pointer(&dlerror))
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
package purego
|
||||
|
||||
// Source for constants: https://opensource.apple.com/source/dyld/dyld-360.14/include/dlfcn.h.auto.html
|
||||
|
||||
const (
|
||||
RTLD_LAZY = 0x1 // Relocations are performed at an implementation-dependent time.
|
||||
RTLD_NOW = 0x2 // Relocations are performed when the object is loaded.
|
||||
RTLD_LOCAL = 0x4 // All symbols are not made available for relocation processing by other modules.
|
||||
RTLD_GLOBAL = 0x8 // All symbols are available for relocation processing of other modules.
|
||||
)
|
||||
|
||||
//go:cgo_import_dynamic purego_dlopen dlopen "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic purego_dlsym dlsym "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic purego_dlerror dlerror "/usr/lib/libSystem.B.dylib"
|
||||
//go:cgo_import_dynamic purego_dlclose dlclose "/usr/lib/libSystem.B.dylib"
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
package purego
|
||||
|
||||
// Source for constants: https://codebrowser.dev/glibc/glibc/bits/dlfcn.h.html
|
||||
|
||||
const (
|
||||
RTLD_LAZY = 0x00001 // Relocations are performed at an implementation-dependent time.
|
||||
RTLD_NOW = 0x00002 // Relocations are performed when the object is loaded.
|
||||
RTLD_LOCAL = 0x00000 // All symbols are not made available for relocation processing by other modules.
|
||||
RTLD_GLOBAL = 0x00100 // All symbols are available for relocation processing of other modules.
|
||||
)
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build !cgo
|
||||
|
||||
package purego
|
||||
|
||||
// if there is no Cgo we must link to each of the functions from dlfcn.h
|
||||
// then the functions are called inside dlfcn_stubs.s
|
||||
|
||||
//go:cgo_import_dynamic purego_dlopen dlopen "libdl.so.2"
|
||||
//go:cgo_import_dynamic purego_dlsym dlsym "libdl.so.2"
|
||||
//go:cgo_import_dynamic purego_dlerror dlerror "libdl.so.2"
|
||||
//go:cgo_import_dynamic purego_dlclose dlclose "libdl.so.2"
|
||||
|
||||
// on amd64 we don't need the following line - on 386 we do...
|
||||
// anyway - with those lines the output is better (but doesn't matter) - without it on amd64 we get multiple DT_NEEDED with "libc.so.6" etc
|
||||
|
||||
//go:cgo_import_dynamic _ _ "libdl.so.2"
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build darwin || (linux && !cgo)
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func dlopen(path *byte, mode int) (ret uintptr)
|
||||
TEXT dlopen(SB), NOSPLIT, $0-0
|
||||
JMP purego_dlopen(SB)
|
||||
RET
|
||||
|
||||
// func dlsym(handle uintptr, symbol *byte) (ret uintptr)
|
||||
TEXT dlsym(SB), NOSPLIT, $0-0
|
||||
JMP purego_dlsym(SB)
|
||||
RET
|
||||
|
||||
// func dlerror() (ret *byte)
|
||||
TEXT dlerror(SB), NOSPLIT, $0-0
|
||||
JMP purego_dlerror(SB)
|
||||
RET
|
||||
|
||||
// func dlclose(handle uintptr) (ret int)
|
||||
TEXT dlclose(SB), NOSPLIT, $0-0
|
||||
JMP purego_dlclose(SB)
|
||||
RET
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build dummy
|
||||
|
||||
// This file exists purely to prevent the Go toolchain from stripping
|
||||
// away the C source directories and files when `go mod vendor` is used
|
||||
// to populate a `vendor/` directory of a project depending on this package.
|
||||
|
||||
package purego
|
||||
|
||||
import (
|
||||
_ "github.com/ebitengine/purego/internal/abi"
|
||||
)
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build darwin || linux
|
||||
|
||||
package purego
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego/internal/strings"
|
||||
)
|
||||
|
||||
// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
|
||||
// It panics if Dlsym fails.
|
||||
//
|
||||
// Windows does not support this function.
|
||||
func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
|
||||
sym := Dlsym(handle, name)
|
||||
if sym == 0 {
|
||||
panic("purego: couldn't find symbol: " + Dlerror())
|
||||
}
|
||||
RegisterFunc(fptr, sym)
|
||||
}
|
||||
|
||||
// RegisterFunc takes a pointer to a Go function representing the calling convention of the C function.
|
||||
// fptr will be set to a function that when called will call the C function given by cfn with the
|
||||
// parameters passed in the correct registers and stack.
|
||||
//
|
||||
// A panic is produced if the type is not a function pointer or if the function returns more than 1 value.
|
||||
//
|
||||
// These conversions describe how a Go type in the fptr will be used to call
|
||||
// the C function. It is important to note that there is no way to verify that fptr
|
||||
// matches the C function. This also holds true for struct types where the padding
|
||||
// needs to be ensured to match that of C; RegisterFunc does not verify this.
|
||||
//
|
||||
// Type Conversions (Go => C)
|
||||
//
|
||||
// string <=> char*
|
||||
// bool <=> _Bool
|
||||
// uintptr <=> uintptr_t
|
||||
// uint <=> uint32_t or uint64_t
|
||||
// uint8 <=> uint8_t
|
||||
// uint16 <=> uint16_t
|
||||
// uint32 <=> uint32_t
|
||||
// uint64 <=> uint64_t
|
||||
// int <=> int32_t or int64_t
|
||||
// int8 <=> int8_t
|
||||
// int16 <=> int16_t
|
||||
// int32 <=> int32_t
|
||||
// int64 <=> int64_t
|
||||
// float32 <=> float (WIP)
|
||||
// float64 <=> double (WIP)
|
||||
// struct <=> struct (WIP)
|
||||
// func <=> C function
|
||||
// unsafe.Pointer, *T <=> void*
|
||||
// []T => void*
|
||||
//
|
||||
// There is a special case when the last argument of fptr is a variadic interface (or []interface}
|
||||
// it will be expanded into a call to the C function as if it had the arguments in that slice.
|
||||
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg.
|
||||
// This is not the same as C variadic.
|
||||
//
|
||||
// There are some limitations when using RegisterFunc on Linux. First, there is no support for function arguments.
|
||||
// Second, float32 and float64 arguments and return values do not work when CGO_ENABLED=1. Otherwise, Linux
|
||||
// has the same feature parity as Darwin.
|
||||
//
|
||||
// Windows does not support this function.
|
||||
func RegisterFunc(fptr interface{}, cfn uintptr) {
|
||||
fn := reflect.ValueOf(fptr).Elem()
|
||||
ty := fn.Type()
|
||||
if ty.Kind() != reflect.Func {
|
||||
panic("purego: fptr must be a function pointer")
|
||||
}
|
||||
if ty.NumOut() > 1 {
|
||||
panic("purego: function can only return zero or one values")
|
||||
}
|
||||
if cfn == 0 {
|
||||
panic("purego: cfn is nil")
|
||||
}
|
||||
{
|
||||
// this code checks how many registers and stack this function will use
|
||||
// to avoid crashing with too many arguments
|
||||
var ints int
|
||||
var floats int
|
||||
var stack int
|
||||
for i := 0; i < ty.NumIn(); i++ {
|
||||
arg := ty.In(i)
|
||||
switch arg.Kind() {
|
||||
case reflect.String, reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Ptr, reflect.UnsafePointer, reflect.Slice,
|
||||
reflect.Func, reflect.Bool:
|
||||
if ints < numOfIntegerRegisters() {
|
||||
ints++
|
||||
} else {
|
||||
stack++
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if floats < 8 {
|
||||
floats++
|
||||
} else {
|
||||
stack++
|
||||
}
|
||||
default:
|
||||
panic("purego: unsupported kind " + arg.Kind().String())
|
||||
}
|
||||
}
|
||||
if ints+stack > maxArgs || floats+stack > maxArgs {
|
||||
panic("purego: too many arguments")
|
||||
}
|
||||
}
|
||||
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
|
||||
if len(args) > 0 {
|
||||
if variadic, ok := args[len(args)-1].Interface().([]interface{}); ok {
|
||||
// subtract one from args bc the last argument in args is []interface{}
|
||||
// which we are currently expanding
|
||||
tmp := make([]reflect.Value, len(args)-1+len(variadic))
|
||||
n := copy(tmp, args[:len(args)-1])
|
||||
for i, v := range variadic {
|
||||
tmp[n+i] = reflect.ValueOf(v)
|
||||
}
|
||||
args = tmp
|
||||
}
|
||||
}
|
||||
var sysargs [maxArgs]uintptr
|
||||
var stack = sysargs[numOfIntegerRegisters():]
|
||||
var floats [8]float64
|
||||
var numInts int
|
||||
var numFloats int
|
||||
var numStack int
|
||||
addStack := func(x uintptr) {
|
||||
stack[numStack] = x
|
||||
numStack++
|
||||
}
|
||||
addInt := func(x uintptr) {
|
||||
if numInts >= numOfIntegerRegisters() {
|
||||
addStack(x)
|
||||
} else {
|
||||
sysargs[numInts] = x
|
||||
numInts++
|
||||
}
|
||||
}
|
||||
var keepAlive []interface{}
|
||||
defer func() {
|
||||
runtime.KeepAlive(keepAlive)
|
||||
}()
|
||||
for _, v := range args {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
ptr := strings.CString(v.String())
|
||||
keepAlive = append(keepAlive, ptr)
|
||||
addInt(uintptr(unsafe.Pointer(ptr)))
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
addInt(uintptr(v.Uint()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
addInt(uintptr(v.Int()))
|
||||
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
|
||||
keepAlive = append(keepAlive, v.Pointer())
|
||||
addInt(v.Pointer())
|
||||
case reflect.Func:
|
||||
addInt(NewCallback(v.Interface()))
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
addInt(1)
|
||||
} else {
|
||||
addInt(0)
|
||||
}
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if numFloats < len(floats) {
|
||||
floats[numFloats] = v.Float()
|
||||
numFloats++
|
||||
} else {
|
||||
addStack(uintptr(math.Float64bits(v.Float())))
|
||||
}
|
||||
default:
|
||||
panic("purego: unsupported kind: " + v.Kind().String())
|
||||
}
|
||||
}
|
||||
// TODO: support structs
|
||||
syscall := syscall9Args{
|
||||
cfn,
|
||||
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], sysargs[6], sysargs[7], sysargs[8],
|
||||
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
|
||||
0, 0, 0}
|
||||
runtime_cgocall(syscall9XABI0, unsafe.Pointer(&syscall))
|
||||
r1, r2 := syscall.r1, syscall.r2
|
||||
|
||||
if ty.NumOut() == 0 {
|
||||
return nil
|
||||
}
|
||||
outType := ty.Out(0)
|
||||
v := reflect.New(outType).Elem()
|
||||
switch outType.Kind() {
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
v.SetUint(uint64(r1))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
v.SetInt(int64(r1))
|
||||
case reflect.Bool:
|
||||
v.SetBool(r1 != 0)
|
||||
case reflect.UnsafePointer:
|
||||
// We take the address and then dereference it to trick go vet from creating a possible miss-use of unsafe.Pointer
|
||||
v.SetPointer(*(*unsafe.Pointer)(unsafe.Pointer(&r1)))
|
||||
case reflect.Ptr:
|
||||
v = reflect.NewAt(outType, unsafe.Pointer(&r1)).Elem()
|
||||
case reflect.Func:
|
||||
// wrap this C function in a nicely typed Go function
|
||||
v = reflect.New(outType)
|
||||
RegisterFunc(v.Interface(), r1)
|
||||
case reflect.String:
|
||||
v.SetString(strings.GoString(r1))
|
||||
case reflect.Float32, reflect.Float64:
|
||||
// NOTE: r2 is only the floating return value on 64bit platforms.
|
||||
// On 32bit platforms r2 is the upper part of a 64bit return.
|
||||
v.SetFloat(math.Float64frombits(uint64(r2)))
|
||||
default:
|
||||
panic("purego: unsupported return kind: " + outType.Kind().String())
|
||||
}
|
||||
return []reflect.Value{v}
|
||||
})
|
||||
fn.Set(v)
|
||||
}
|
||||
|
||||
func numOfIntegerRegisters() int {
|
||||
switch runtime.GOARCH {
|
||||
case "arm64":
|
||||
return 8
|
||||
case "amd64":
|
||||
return 6
|
||||
default:
|
||||
panic("purego: unknown GOARCH (" + runtime.GOARCH + ")")
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build darwin || linux
|
||||
|
||||
package purego
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname runtime_cgocall runtime.cgocall
|
||||
func runtime_cgocall(fn uintptr, arg unsafe.Pointer) int32 // from runtime/sys_libc.go
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Macros for transitioning from the host ABI to Go ABI0.
|
||||
//
|
||||
// These save the frame pointer, so in general, functions that use
|
||||
// these should have zero frame size to suppress the automatic frame
|
||||
// pointer, though it's harmless to not do this.
|
||||
|
||||
#ifdef GOOS_windows
|
||||
|
||||
// REGS_HOST_TO_ABI0_STACK is the stack bytes used by
|
||||
// PUSH_REGS_HOST_TO_ABI0.
|
||||
#define REGS_HOST_TO_ABI0_STACK (28*8 + 8)
|
||||
|
||||
// PUSH_REGS_HOST_TO_ABI0 prepares for transitioning from
|
||||
// the host ABI to Go ABI0 code. It saves all registers that are
|
||||
// callee-save in the host ABI and caller-save in Go ABI0 and prepares
|
||||
// for entry to Go.
|
||||
//
|
||||
// Save DI SI BP BX R12 R13 R14 R15 X6-X15 registers and the DF flag.
|
||||
// Clear the DF flag for the Go ABI.
|
||||
// MXCSR matches the Go ABI, so we don't have to set that,
|
||||
// and Go doesn't modify it, so we don't have to save it.
|
||||
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||
PUSHFQ \
|
||||
CLD \
|
||||
ADJSP $(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||
MOVQ DI, (0*0)(SP) \
|
||||
MOVQ SI, (1*8)(SP) \
|
||||
MOVQ BP, (2*8)(SP) \
|
||||
MOVQ BX, (3*8)(SP) \
|
||||
MOVQ R12, (4*8)(SP) \
|
||||
MOVQ R13, (5*8)(SP) \
|
||||
MOVQ R14, (6*8)(SP) \
|
||||
MOVQ R15, (7*8)(SP) \
|
||||
MOVUPS X6, (8*8)(SP) \
|
||||
MOVUPS X7, (10*8)(SP) \
|
||||
MOVUPS X8, (12*8)(SP) \
|
||||
MOVUPS X9, (14*8)(SP) \
|
||||
MOVUPS X10, (16*8)(SP) \
|
||||
MOVUPS X11, (18*8)(SP) \
|
||||
MOVUPS X12, (20*8)(SP) \
|
||||
MOVUPS X13, (22*8)(SP) \
|
||||
MOVUPS X14, (24*8)(SP) \
|
||||
MOVUPS X15, (26*8)(SP)
|
||||
|
||||
#define POP_REGS_HOST_TO_ABI0() \
|
||||
MOVQ (0*0)(SP), DI \
|
||||
MOVQ (1*8)(SP), SI \
|
||||
MOVQ (2*8)(SP), BP \
|
||||
MOVQ (3*8)(SP), BX \
|
||||
MOVQ (4*8)(SP), R12 \
|
||||
MOVQ (5*8)(SP), R13 \
|
||||
MOVQ (6*8)(SP), R14 \
|
||||
MOVQ (7*8)(SP), R15 \
|
||||
MOVUPS (8*8)(SP), X6 \
|
||||
MOVUPS (10*8)(SP), X7 \
|
||||
MOVUPS (12*8)(SP), X8 \
|
||||
MOVUPS (14*8)(SP), X9 \
|
||||
MOVUPS (16*8)(SP), X10 \
|
||||
MOVUPS (18*8)(SP), X11 \
|
||||
MOVUPS (20*8)(SP), X12 \
|
||||
MOVUPS (22*8)(SP), X13 \
|
||||
MOVUPS (24*8)(SP), X14 \
|
||||
MOVUPS (26*8)(SP), X15 \
|
||||
ADJSP $-(REGS_HOST_TO_ABI0_STACK - 8) \
|
||||
POPFQ
|
||||
|
||||
#else
|
||||
// SysV ABI
|
||||
|
||||
#define REGS_HOST_TO_ABI0_STACK (6*8)
|
||||
|
||||
// SysV MXCSR matches the Go ABI, so we don't have to set that,
|
||||
// and Go doesn't modify it, so we don't have to save it.
|
||||
// Both SysV and Go require DF to be cleared, so that's already clear.
|
||||
// The SysV and Go frame pointer conventions are compatible.
|
||||
#define PUSH_REGS_HOST_TO_ABI0() \
|
||||
ADJSP $(REGS_HOST_TO_ABI0_STACK) \
|
||||
MOVQ BP, (5*8)(SP) \
|
||||
LEAQ (5*8)(SP), BP \
|
||||
MOVQ BX, (0*8)(SP) \
|
||||
MOVQ R12, (1*8)(SP) \
|
||||
MOVQ R13, (2*8)(SP) \
|
||||
MOVQ R14, (3*8)(SP) \
|
||||
MOVQ R15, (4*8)(SP)
|
||||
|
||||
#define POP_REGS_HOST_TO_ABI0() \
|
||||
MOVQ (0*8)(SP), BX \
|
||||
MOVQ (1*8)(SP), R12 \
|
||||
MOVQ (2*8)(SP), R13 \
|
||||
MOVQ (3*8)(SP), R14 \
|
||||
MOVQ (4*8)(SP), R15 \
|
||||
MOVQ (5*8)(SP), BP \
|
||||
ADJSP $-(REGS_HOST_TO_ABI0_STACK)
|
||||
|
||||
#endif
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Macros for transitioning from the host ABI to Go ABI0.
|
||||
//
|
||||
// These macros save and restore the callee-saved registers
|
||||
// from the stack, but they don't adjust stack pointer, so
|
||||
// the user should prepare stack space in advance.
|
||||
// SAVE_R19_TO_R28(offset) saves R19 ~ R28 to the stack space
|
||||
// of ((offset)+0*8)(RSP) ~ ((offset)+9*8)(RSP).
|
||||
//
|
||||
// SAVE_F8_TO_F15(offset) saves F8 ~ F15 to the stack space
|
||||
// of ((offset)+0*8)(RSP) ~ ((offset)+7*8)(RSP).
|
||||
//
|
||||
// R29 is not saved because Go will save and restore it.
|
||||
|
||||
#define SAVE_R19_TO_R28(offset) \
|
||||
STP (R19, R20), ((offset)+0*8)(RSP) \
|
||||
STP (R21, R22), ((offset)+2*8)(RSP) \
|
||||
STP (R23, R24), ((offset)+4*8)(RSP) \
|
||||
STP (R25, R26), ((offset)+6*8)(RSP) \
|
||||
STP (R27, g), ((offset)+8*8)(RSP)
|
||||
#define RESTORE_R19_TO_R28(offset) \
|
||||
LDP ((offset)+0*8)(RSP), (R19, R20) \
|
||||
LDP ((offset)+2*8)(RSP), (R21, R22) \
|
||||
LDP ((offset)+4*8)(RSP), (R23, R24) \
|
||||
LDP ((offset)+6*8)(RSP), (R25, R26) \
|
||||
LDP ((offset)+8*8)(RSP), (R27, g) /* R28 */
|
||||
#define SAVE_F8_TO_F15(offset) \
|
||||
FSTPD (F8, F9), ((offset)+0*8)(RSP) \
|
||||
FSTPD (F10, F11), ((offset)+2*8)(RSP) \
|
||||
FSTPD (F12, F13), ((offset)+4*8)(RSP) \
|
||||
FSTPD (F14, F15), ((offset)+6*8)(RSP)
|
||||
#define RESTORE_F8_TO_F15(offset) \
|
||||
FLDPD ((offset)+0*8)(RSP), (F8, F9) \
|
||||
FLDPD ((offset)+2*8)(RSP), (F10, F11) \
|
||||
FLDPD ((offset)+4*8)(RSP), (F12, F13) \
|
||||
FLDPD ((offset)+6*8)(RSP), (F14, F15)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
//go:build dummy
|
||||
|
||||
// Package abi is a dummy package that prevents go tooling from stripping the C dependencies.
|
||||
package abi
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
|
||||
|
||||
package cgo
|
||||
|
||||
// this file is placed inside internal/cgo and not package purego
|
||||
// because Cgo and assembly files can't be in the same package.
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -ldl
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct syscall9Args {
|
||||
uintptr_t fn;
|
||||
uintptr_t a1, a2, a3, a4, a5, a6, a7, a8, a9;
|
||||
uintptr_t f1, f2, f3, f4, f5, f6, f7, f8;
|
||||
uintptr_t r1, r2, err;
|
||||
} syscall9Args;
|
||||
|
||||
void syscall9(struct syscall9Args *args) {
|
||||
assert((args->f1|args->f2|args->f3|args->f4|args->f5|args->f6|args->f7|args->f8) == 0);
|
||||
uintptr_t (*func_name)(uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9);
|
||||
*(void**)(&func_name) = (void*)(args->fn);
|
||||
uintptr_t r1 = func_name(args->a1,args->a2,args->a3,args->a4,args->a5,args->a6,args->a7,args->a8,args->a9);
|
||||
args->r1 = r1;
|
||||
args->err = errno;
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// assign purego.syscall9XABI0 to the C version of this function.
|
||||
var Syscall9XABI0 = unsafe.Pointer(C.syscall9)
|
||||
|
||||
// all that is needed is to assign each dl function because then its
|
||||
// symbol will then be made available to the linker and linked to inside dlfcn.go
|
||||
var (
|
||||
_ = C.dlopen
|
||||
_ = C.dlsym
|
||||
_ = C.dlerror
|
||||
_ = C.dlclose
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func Syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
|
||||
args := C.syscall9Args{C.uintptr_t(fn), C.uintptr_t(a1), C.uintptr_t(a2), C.uintptr_t(a3),
|
||||
C.uintptr_t(a4), C.uintptr_t(a5), C.uintptr_t(a6),
|
||||
C.uintptr_t(a7), C.uintptr_t(a8), C.uintptr_t(a9), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
C.syscall9(&args)
|
||||
return uintptr(args.r1), uintptr(args.r2), uintptr(args.err)
|
||||
}
|
||||
Loaded 100 of 754 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user