Skip to content

Commit

Permalink
Amber v3.2 release.
Browse files Browse the repository at this point in the history
- Major loader update!
  - Added TLS callback support
  - Added forwarded imports support
  - Removed GetProcAddress and LoadLibrary WinAPI usage
  - Switched to NTDLL WinApi functions
  - Wiper code improved
- Added lite loader option for appending PE files on the fly!
- Added experimental raw syscall loader
- Added static build flags in makefile
- File name bug fixed
- Dockerfile updated
- Github workflows added
- README updated
  • Loading branch information
EgeBalci committed Jun 24, 2023
1 parent a331b34 commit c33a6e3
Show file tree
Hide file tree
Showing 79 changed files with 3,477 additions and 2,227 deletions.
Binary file added .github/img/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/img/loader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
61 changes: 61 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

name: build

on:
push:
branches: [ "master" ]

jobs:
linux-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Install Keystone
run: ./install-keystone.sh
- name: Build for Linux
run: make
- name: 'Upload Artifact'
uses: actions/upload-artifact@v3
with:
name: amber_linux
path: amber
retention-days: 5
macos-run:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Install Keystone
run: ./install-keystone.sh
- name: Build for MacOS
run: make
- name: 'Upload Artifact'
uses: actions/upload-artifact@v3
with:
name: amber_darwin
path: amber
retention-days: 5

windows-build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19
- name: Build for Windows
run: make
- name: 'Upload Artifact'
uses: actions/upload-artifact@v3
with:
name: amber.exe
path: amber.exe
retention-days: 5
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.15-buster as builder
FROM golang:1.20 as builder

RUN apt-get update && apt-get -y install \
build-essential \
Expand All @@ -19,10 +19,11 @@ RUN cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLVM_TARGETS_TO_B
RUN make -j8
RUN make install && ldconfig

# RUN mkdir /root/amber
WORKDIR /root
RUN git clone https://github.com/egebalci/amber
WORKDIR /root/amber
RUN go build -o /root/bin/amber -ldflags '-w -s -extldflags -static' -trimpath main.go
RUN go build -trimpath -buildvcs=false -ldflags="-extldflags=-static -s -w" -o /root/bin/amber main.go

FROM scratch
COPY --from=builder /root/bin/amber /amber
Expand Down
19 changes: 5 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
normal:
go build -ldflags="-s -w" -trimpath -o amber
386:
CGO_ENABLED=1 GOARCH=386 go build -ldflags="-s -w" -trimpath -o amber
linux_amd64:
GOOS=linux CGO_ENABLED=1 GOARCH=amd64 go build -ldflags="-s -w" -trimpath -o amber
linux_386:
GOOS=linux CGO_ENABLED=1 GOARCH=386 go build -ldflags="-s -w" -trimpath -o amber
windows_amd64:
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L`pwd`/build/lib/" CXX=x86_64-w64-mingw32-g++ CC=x86_64-w64-mingw32-gcc go build -ldflags="-s -w" -trimpath -o amber.exe
windows_386:
GOOS=windows GOARCH=386 CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L`pwd`/build/lib32/" CXX=i686-w64-mingw32-g++ CC=i686-w64-mingw32-gcc go build -ldflags="-s -w" -trimpath -o amber32.exe
darwin:
GOOS=darwin CGO_ENABLED=1 CGO_LDFLAGS="-lkeystone -L`pwd`/build/lib/" go build -ldflags="-s -w" -trimpath -o amber
BUILD=go build
BUILD_FLAGS=-trimpath -buildvcs=false -ldflags="-extldflags=-static -s -w -X github.com/egebalci/amber/config.Version=$$(git log --pretty=format:'v1.0.%at-%h' -n 1)"

default:
${BUILD} ${BUILD_FLAGS} -o amber
57 changes: 27 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

<p align="center">
<img src="https://github.com/EgeBalci/amber/raw/master/img/banner.png">
<img src="./.github/img/banner.png">
<br/>
<a href="https://github.com/EgeBalci/amber">
<img src="https://img.shields.io/badge/version-3.1.0-green.svg?style=flat-square">
<img src="https://img.shields.io/badge/version-3.2.0-green.svg?style=flat-square">
</a>
<a href="https://goreportcard.com/report/github.com/egebalci/amber">
<img src="https://goreportcard.com/badge/github.com/egebalci/amber?style=flat-square">
Expand All @@ -23,18 +23,15 @@

Amber is a position-independent(reflective) PE loader that enables in-memory execution of native PE files(EXE, DLL, SYS...). It enables stealthy in-memory payload deployment that can be used to bypass anti-virus, firewall, IDS, IPS products, and application white-listing mitigations. Reflective payloads generated by Amber can either be staged from a remote server or executed directly in memory much like a generic shellcode. By default, every generated payload is encoded using the new generation [SGN encoder](https://github.com/EgeBalci/sgn). Amber uses [CRC32_API](https://github.com/EgeBalci/crc32_api) and [IAT_API](https://github.com/EgeBalci/iat_api) for inconspicuously resolving the Windows API function addresses. After the PE file is loaded and executed in memory, the reflective payload is erased for evading memory scanners.

Developed By Ege Balcı @[PRODAFT](https://prodaft.com).

# Installation

Pre-compiled binaries can be found under [releases](https://github.com/EgeBalci/amber/releases).

***Building From Source***

The only dependency for building the source is the [keystone engine](https://github.com/keystone-engine/keystone), follow [these](https://github.com/keystone-engine/keystone/blob/master/docs/COMPILE.md) instructions for installing the library. Once libkeystone is installed on the system, simply just go get it ツ

```
go get github.com/EgeBalci/amber
go install github.com/EgeBalci/amber@latest
```

***Docker Install***
Expand All @@ -49,7 +46,7 @@ docker run -it egee/amber
# Usage

<p align="center">
<img src="https://github.com/EgeBalci/amber/raw/master/img/usage.gif">
<img src="./.github/img/usage.gif">
</p>

The following table lists switches supported by the amber.
Expand All @@ -60,47 +57,47 @@ The following table lists switches supported by the amber.
<th>Type</th>
<th>Description</th>
</tr>

<tr>
<td><strong>-b,--build</strong></td>
<td><var>bool</var></td>
<td>Build EXE stub that executes the generated reflective payload</td>
<td><strong>-f,--file</strong></td>
<td><var>string</var></td>
<td>Input PE file.</td>
</tr>

<tr>
<td><strong>-o,--out</strong></td>
<td><var>string</var></td>
<td>Output binary payload file name.</td>
</tr>

<tr>
<td><strong>-e</strong></td>
<td><var>int</var></td>
<td>Number of times to encode the generated reflective payload</td>
</tr>

<tr>
<td><strong>-f,--file</strong></td>
<td><var>string</var></td>
<td>Input PE file.</td>
</tr>

<tr>
<td><strong>-iat</strong></td>
<td><strong>--iat</strong></td>
<td><var>bool</var></td>
<td>Use IAT API resolver block instead of CRC API resolver block</td>
</tr>

<tr>
<td><strong>-ignore-checks</strong></td>
<td><var>bool</var></td>
<td>Ignore integrity check errors.</td>
</tr>

<tr>
<td><strong>-max</strong></td>
<td><strong>-l</strong></td>
<td><var>int</var></td>
<td>Maximum number of bytes for obfuscation (default 5)</td>
</tr>

<tr>
<td><strong>-s,--stub</strong></td>
<td><var>string</var></td>
<td>Use custom stub file for executing the generated reflective payload (currently very unstable)</td>
<td><strong>--sys</strong></td>
<td><var>bool</var></td>
<td>Perform raw syscalls. (only x64)</td>
</tr>

<tr>
<td><strong>--scrape</strong></td>
<td><var>bool</var></td>
<td>Scrape magic byte and DOS stub from PE.</td>
</tr>

</table>
Expand All @@ -112,9 +109,9 @@ The following table lists switches supported by the amber.
```
amber -f test.exe
```
- Generate reflective payload and build EXE stub for executing it.
- Generate reflective payload with IAT API resolver and encode the final payload 10 times.
```
amber -build -f test.exe
amber -e 10 --iat -f test.exe
```

***Docker Usage***
Expand Down
114 changes: 59 additions & 55 deletions config/options.go
Original file line number Diff line number Diff line change
@@ -1,79 +1,83 @@
package config

import (
"errors"
"flag"
"fmt"
"os"

amber "github.com/EgeBalci/amber/pkg"
sgn "github.com/EgeBalci/sgn/pkg"
"github.com/fatih/color"
"github.com/EgeBalci/amber/utils"
"github.com/alecthomas/kong"
)

var usageStr = `
Usage: amber [options]
Options:
-f, --file <file> Input PE file
-s, --stub <file> Use custom stub file (experimental)
-m, --max <int> Maximum number of bytes for obfuscation
-e, <int> 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
`
const Version = "3.2.0"

// PrintUsageErrorAndDie ...
func PrintUsageErrorAndDie(err error) {
color.Red(err.Error())
fmt.Println(usageStr)
os.Exit(1)
func HelpPrompt(options kong.HelpOptions, ctx *kong.Context) error {
err := kong.DefaultHelpPrinter(options, ctx)
if err != nil {
return err
}
return nil
}

// PrintHelpAndDie ...
func PrintHelpAndDie() {
fmt.Println(usageStr)
os.Exit(0)
// Main config struct for parsing the TOML file
type Config struct {
FileName string `help:"Input PE file name." name:"file" short:"f"`
OutputFile string `help:"Output binary payload file name." name:"out" short:"o"`
EncodeCount int `help:"Number of times to encode the generated reflective payload." name:"encode" short:"e" default:"1"`
ObfuscationLimit int `help:"Maximum number of bytes for encoder obfuscation." name:"obfuscate-limit" short:"l" default:"5"`
UseIAT bool `help:"Use IAT API resolver block instead of CRC API resolver block." name:"iat"`
UseSyscalls bool `help:"Perform raw syscalls. (only x64)" name:"sys"`
ScrapePeHeaders bool `help:"Scrape magic byte and DOS stub from PE." name:"scrape"`
// IgnoreIntegrity bool `help:"Ignore PE file integrity check errors." name:"ignore"`
Verbose bool `help:"Verbose mode." name:"verbose" short:"v"`
Version kong.VersionFlag
}

// 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()
func Parse() (*Config, error) {

// 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
cfg := new(Config)
parser, err := kong.New(
cfg,
kong.Help(HelpPrompt),
kong.UsageOnError(),
kong.Vars{"version": Version},
kong.ConfigureHelp(kong.HelpOptions{
Summary: true,
}),
)
if err != nil {
return nil, err
}
_, err = parser.Parse(os.Args[1:])
if err != nil {
return 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 cfg.FileName == "" {
utils.PrintErr("no file specified! (-f <empty>)\n")
kong.Help(HelpPrompt)
os.Exit(1)
}

// If -help flag is defined, print help
if *help {
PrintHelpAndDie()
if cfg.OutputFile == "" {
cfg.OutputFile = fmt.Sprintf("%s.bin", cfg.FileName)
}

return bp, encoder, nil
return cfg, nil
}

func (cfg *Config) PrintSummary() {
utils.PrintStatus("File: %s\n", cfg.FileName)
utils.PrintStatus("Encode Count: %d\n", cfg.EncodeCount)
utils.PrintStatus("Obfuscation Limit: %d\n", cfg.ObfuscationLimit)
if cfg.UseIAT {
utils.PrintStatus("API Resolver: IAT\n")
} else {
utils.PrintStatus("API Resolver: CRC\n")
}
if cfg.UseSyscalls {
utils.PrintStatus("Raw Syscalls: True\n")
}
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ 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-20201126033925-686e60d127dc
github.com/alecthomas/kong v0.7.1
github.com/briandowns/spinner v1.11.1
github.com/fatih/color v1.10.0
github.com/sirupsen/logrus v1.9.0
golang.org/x/sys v0.7.0 // indirect
)
Loading

0 comments on commit c33a6e3

Please sign in to comment.