diff --git a/README.md b/README.md index ce80253..f727515 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@
- + @@ -62,7 +62,7 @@ The following table lists switches supported by the amber. - -build + -b,--build bool Build EXE stub that executes the generated reflective payload @@ -74,7 +74,7 @@ The following table lists switches supported by the amber. - -f + -f,--file string Input PE file. @@ -98,7 +98,7 @@ The following table lists switches supported by the amber. - -stub + -s,--stub string Use custom stub file for executing the generated reflective payload (currently very unstable) diff --git a/config/options.go b/config/options.go new file mode 100644 index 0000000..133b8c5 --- /dev/null +++ b/config/options.go @@ -0,0 +1,79 @@ +package config + +import ( + "errors" + "flag" + "fmt" + "os" + + amber "github.com/EgeBalci/amber/pkg" + sgn "github.com/EgeBalci/sgn/pkg" + "github.com/fatih/color" +) + +var usageStr = ` +Usage: amber [options] +Options: + -f, --file Input PE file + -s, --stub Use custom stub file (experimental) + -m, --max Maximum number of bytes for obfuscation + -e, Number of times to encode the generated reflective payload + -b, --build Build EXE stub that executes the generated reflective payload + --iat, Use IAT API resolver block instead of CRC API resolver block + --ignore-checks, Ignore integrity check errors. + -h, Show this message +` + +// PrintUsageErrorAndDie ... +func PrintUsageErrorAndDie(err error) { + color.Red(err.Error()) + fmt.Println(usageStr) + os.Exit(1) +} + +// PrintHelpAndDie ... +func PrintHelpAndDie() { + fmt.Println(usageStr) + os.Exit(0) +} + +// ConfigureOptions accepts a flag set and augments it with agentgo-server +// specific flags. On success, an options structure is returned configured +// based on the selected flags. +func ConfigureOptions(fs *flag.FlagSet, args []string) (*amber.Blueprint, *sgn.Encoder, error) { + + // Create empty options + bp := &amber.Blueprint{} + encoder := sgn.NewEncoder() + + // Define flags + help := fs.Bool("h", false, "Show help message") + fs.StringVar(&bp.FileName, "f", "", "Input PE file") + fs.StringVar(&bp.FileName, "file", "", "Input PE file") + fs.BoolVar(&bp.IAT, "iat", false, "Use IAT API resolver block instead of CRC API resolver block") + fs.BoolVar(&bp.IgnoreIntegrity, "ignore-checks", false, "Ignore integrity check errors.") + fs.StringVar(&bp.CustomStubName, "s", "", "Use custom stub file (experimental)") + fs.StringVar(&bp.CustomStubName, "stub", "", "Use custom stub file (experimental)") + fs.IntVar(&encoder.ObfuscationLimit, "max", 5, "Maximum number of bytes for obfuscation") + fs.IntVar(&encoder.EncodingCount, "e", 1, "Number of times to encode the generated reflective payload") + fs.BoolVar(&bp.BuildStub, "b", false, "Build EXE stub that executes the generated reflective payload") + fs.BoolVar(&bp.BuildStub, "build", false, "Build EXE stub that executes the generated reflective payload") + + // Parse arguments and check for errors + if err := fs.Parse(args); err != nil { + return nil, nil, err + } + + // If it is not help and other args are empty, return error + if (*help == false) && bp.FileName == "" { + err := errors.New("please specify all required arguments") + return nil, nil, err + } + + // If -help flag is defined, print help + if *help { + PrintHelpAndDie() + } + + return bp, encoder, nil +} diff --git a/go.mod b/go.mod index de21ece..0ab1d06 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.15 require ( github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848 github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae - github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251 + github.com/EgeBalci/sgn v0.0.0-20201126033925-686e60d127dc github.com/briandowns/spinner v1.11.1 github.com/fatih/color v1.10.0 ) diff --git a/go.sum b/go.sum index 87097d6..787be93 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae h1:IMOEVXYMrz github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae/go.mod h1:/HCfOmUN3INldcXC0YnFrOtOw3MuRFEQ9cKTT5fZuQ8= github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251 h1:VyTVKce2AzuB6521arwJvyQFHLQ0USNnw/0IZ/RP3bE= github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251/go.mod h1:gI4nYEhbKmf35Q+NPyoX+o1ajkCgabjYjsyu19tmfgM= +github.com/EgeBalci/sgn v0.0.0-20201126033925-686e60d127dc h1:OVYO6tY6ivMDvT/np+bKnkUSIgHRJ4S7hAGcd1ylas8= +github.com/EgeBalci/sgn v0.0.0-20201126033925-686e60d127dc/go.mod h1:gI4nYEhbKmf35Q+NPyoX+o1ajkCgabjYjsyu19tmfgM= github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0= github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -21,4 +23,5 @@ github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/main.go b/main.go index f513d96..728c147 100644 --- a/main.go +++ b/main.go @@ -10,8 +10,8 @@ import ( "strings" "time" + "github.com/EgeBalci/amber/config" amber "github.com/EgeBalci/amber/pkg" - sgn "github.com/EgeBalci/sgn/pkg" "github.com/briandowns/spinner" "github.com/fatih/color" ) @@ -22,28 +22,18 @@ var spinr = spinner.New(spinner.CharSets[9], 30*time.Millisecond) func main() { banner() - bp := new(amber.Blueprint) - encoder := sgn.NewEncoder() - - flag.StringVar(&bp.FileName, "f", "", "Input PE file") - flag.BoolVar(&bp.IAT, "iat", false, "Use IAT API resolver block instead of CRC API resolver block") - flag.BoolVar(&bp.IgnoreIntegrity, "ignore-checks", false, "Ignore integrity check errors.") - flag.StringVar(&bp.CustomStubName, "stub", "", "Use custom stub file (experimental)") - flag.IntVar(&encoder.ObfuscationLimit, "max", 5, "Maximum number of bytes for obfuscation") - flag.IntVar(&encoder.EncodingCount, "e", 1, "Number of times to encode the generated reflective payload") - buildStub := flag.Bool("build", false, "Build EXE stub that executes the generated reflective payload") - - green := color.New(color.FgGreen).Add(color.Bold) - flag.Parse() - - if bp.FileName == "" { - flag.PrintDefaults() - os.Exit(0) + // Create a FlagSet and sets the usage + fs := flag.NewFlagSet(filepath.Base(os.Args[0]), flag.ExitOnError) + // Configure the options from the flags/config file + bp, encoder, err := config.ConfigureOptions(fs, os.Args[1:]) + if err != nil { + config.PrintUsageErrorAndDie(err) } + green := color.New(color.FgGreen).Add(color.Bold) spinr.Start() status("File: %s\n", bp.FileName) - status("Build Stub: %t\n", *buildStub) + status("Build Stub: %t\n", bp.BuildStub) status("Encode Count: %d\n", encoder.EncodingCount) if bp.IAT { status("API: IAT\n") @@ -71,14 +61,13 @@ func main() { eror(err) } - if !*buildStub { + if !bp.BuildStub { bp.FullFileName += ".bin" } else { // Construct EXE stub spinr.Suffix = " Building EXE stub..." payload, err = bp.CompileStub(payload) eror(err) - bp.FullFileName = strings.ReplaceAll(bp.FullFileName, filepath.Ext(bp.FullFileName), "_packed.exe") } spinr.Stop() diff --git a/pkg/amber.go b/pkg/amber.go index 1bf7edd..edabd4e 100644 --- a/pkg/amber.go +++ b/pkg/amber.go @@ -7,7 +7,7 @@ import ( ) // VERSION number -const VERSION = "3.0.0" +const VERSION = "3.1.0" // Blueprint structure contains PE specs, tool parameters and // OS spesific info @@ -19,6 +19,7 @@ type Blueprint struct { IAT bool Resource bool IgnoreIntegrity bool + BuildStub bool CustomStubName string CustomStub []byte // PE specs...