TheWover / donut

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
BSD 3-Clause "New" or "Revised" License
3.53k stars 628 forks source link

Issues with Go binaries #9

Closed aus closed 5 years ago

aus commented 5 years ago

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!

odzhan commented 5 years ago

Currently, donut doesn't support unmanaged EXE/DLL files without relocation information (.reloc). There should have been a check for the PE directory before building the shell code, which is now present. If you try building shellcode from PE file with no .reloc information, you'll receive the following error.

[ Error : This file has no relocation information required for in-memory execution.

Callback addresses in the TLS directory are absolute and are relatively simple to get working without .reloc information. However, code in the actual callback function may also use absolute addresses for data variables, and this is what causes the EXE file to crash the host process. To support relocating the code without .reloc information embedded in the PE file would require a built-in disassembler :) Perhaps it can be implemented in future, because it's certainly doable.

The TLS callbacks for DLL are only executed when the process begins and not for a new thread or when the process ends, which is required. For the moment, I've disabled support for PE files that do not contain relocation information. DLL files will still load, although there are likely to be issues supporting TLS.

aus commented 5 years ago

was using x86 runsc against x64 DLL payload.bin. doh! DLL works. 😄 see this comment's revision history for a full look at my stupidity. thanks @odzhan for setting me straight.

odzhan commented 5 years ago

No problem! I've done it myself many times during development :grin:

aus commented 4 years ago

For those seeking more information about Go and donut, @odzhan added some checks to ensure the target PE has a .reloc section. Go EXEs do not normally build with .relocs (but Go DLLs do). donut will reject PEs without .relocs, thus Go EXEs do not work without some extra steps.

To get Go EXEs to work with donut, you'll need to build your executable with -buildmode=pie. Unfortunately, this buildmode is not supported on windows/x86 and windows/amd64 unless you build with this patched version of Go. With this patched version of Go, you can just do a go build -buildmode=pie and donut should now accept the EXE since it will have a .reloc section.

update: Go 1.15 supports buildmode=pie by default for Windows executables.

S3cur3Th1sSh1t commented 3 years ago

If someone faces the same problem with gcc compiled executables -> Add those flags to the compiler -Wl,--dynamicbase,--export-all-symbols

https://stackoverflow.com/questions/19451652/mingw-relocation-table