Post

N0xshell-Encryptor

N0xshell-Encryptor

What is it?

A standalone command-line tool that takes a beacon/payload binary and an encryption key as arguments, encrypts the binary with AES-256 using the Windows Crypto API, and outputs a .enc file. The output is designed to be embedded in the loader’s .rsrc section as a resource.

How it works

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Usage:
  encryptor.exe beacon.exe MySecret123
  encryptor.exe -file beacon.exe -key MySecret123

ReadFileToBuffer(szBeaconPath):
  CreateFileW + GetFileSize + HeapAlloc + ReadFile
  → pBeaconFile (raw bytes), sBeaconSize

AesEncrypt(pBeaconFile, sBeaconSize, szEncryptionKey, keyLen):
  
  CryptAcquireContextW(MS_ENH_RSA_AES_PROV_W, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)
  → hProv: handle to AES crypto provider

  CryptCreateHash(hProv, CALG_SHA_256)
  → hHash: SHA-256 hash object

  CryptHashData(hHash, szEncryptionKey, keyLen)
  → SHA-256 hash of the key string (e.g. "MySecret123")

  CryptDeriveKey(hProv, CALG_AES_256, hHash)
  → hKey: AES-256 key derived from the SHA-256 of the passphrase

  HeapAlloc(sBeaconSize + 16)   ← +16 for AES block padding
  memcpy(pEncrypted, pBeaconFile, sBeaconSize)

  CryptEncrypt(hKey, 0, TRUE, 0, pEncrypted, &dwEncryptedSize, sBeaconSize + 16)
  → In-place AES-256 encryption

  return pEncrypted, sEncryptedSize

Output:
  CreateFileW("beacon.exe.enc", GENERIC_WRITE, CREATE_ALWAYS)
  WriteFile(encrypted bytes)

Console output tells you next steps:
  1. Add beacon.exe.enc to .rsrc as RCDATA type 8888, ID 9001
  2. Use loader.exe -key "MySecret123" to decrypt + execute

Key derivation:
  passphrase → SHA-256 → 256-bit AES key
  (CryptDeriveKey with CALG_SHA_256 hash as the source material)

The key derivation is worth noting: the encryption key isn’t used directly as AES key material. The passphrase string is first hashed with SHA-256, and CryptDeriveKey uses that hash to derive the actual 256-bit AES key. This means you can use an arbitrary-length human-readable string as the key and the crypto API handles turning it into the right byte length.

The +16 padding on the output buffer accounts for AES block alignment — AES-256 in CBC mode pads the plaintext to the nearest 16-byte block boundary, so the encrypted output can be up to 15 bytes longer than the input. The final sEncryptedSize reflects the actual padded length.

encryptor.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib, "advapi32.lib")

/*
	ENCRYPTION TOOL
	Encrypts beacon with AES-256 and outputs encrypted binary file
	Usage: encryptor.exe beacon.exe encryption_key
	Output: beacon.exe.enc (encrypted binary file)
*/

PBYTE ReadFileToBuffer(_In_ LPWSTR szFilePath, _Out_ SIZE_T* pFileSize) {
	HANDLE hFile = INVALID_HANDLE_VALUE;
	PBYTE pFileBuffer = NULL;
	DWORD dwFileSize = 0;
	DWORD dwBytesRead = 0;

	hFile = CreateFileW(szFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE) {
		printf("[!] CreateFileW failed: %d\n", GetLastError());
		return NULL;
	}

	dwFileSize = GetFileSize(hFile, NULL);
	if (dwFileSize == INVALID_FILE_SIZE || dwFileSize == 0) {
		printf("[!] Invalid file size\n");
		CloseHandle(hFile);
		return NULL;
	}

	pFileBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwFileSize);
	if (!pFileBuffer) {
		printf("[!] HeapAlloc failed\n");
		CloseHandle(hFile);
		return NULL;
	}

	if (!ReadFile(hFile, pFileBuffer, dwFileSize, &dwBytesRead, NULL) || dwBytesRead != dwFileSize) {
		printf("[!] ReadFile failed: %d\n", GetLastError());
		HeapFree(GetProcessHeap(), 0, pFileBuffer);
		CloseHandle(hFile);
		return NULL;
	}

	*pFileSize = dwFileSize;
	CloseHandle(hFile);
	printf("[+] File read: %lu bytes\n", dwFileSize);
	return pFileBuffer;
}

PBYTE AesEncrypt(_In_ PBYTE pPlaintext, _In_ SIZE_T sPlaintextSize, _In_ PBYTE pbKey, _In_ SIZE_T sKeySize, _Out_ SIZE_T* pEncryptedSize) {
	HCRYPTPROV hProv = 0;
	HCRYPTKEY hKey = 0;
	HCRYPTHASH hHash = 0;
	PBYTE pEncrypted = NULL;
	DWORD dwEncryptedSize = 0;

	if (!pPlaintext || !sPlaintextSize || !pbKey || !sKeySize) {
		printf("[!] Invalid parameters\n");
		return NULL;
	}

	if (!CryptAcquireContextW(&hProv, NULL, MS_ENH_RSA_AES_PROV_W, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
		printf("[!] CryptAcquireContextW failed: %d\n", GetLastError());
		return NULL;
	}

	if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
		printf("[!] CryptCreateHash failed: %d\n", GetLastError());
		CryptReleaseContext(hProv, 0);
		return NULL;
	}

	if (!CryptHashData(hHash, pbKey, (DWORD)sKeySize, 0)) {
		printf("[!] CryptHashData failed: %d\n", GetLastError());
		CryptDestroyHash(hHash);
		CryptReleaseContext(hProv, 0);
		return NULL;
	}

	if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0, &hKey)) {
		printf("[!] CryptDeriveKey failed: %d\n", GetLastError());
		CryptDestroyHash(hHash);
		CryptReleaseContext(hProv, 0);
		return NULL;
	}

	dwEncryptedSize = (DWORD)sPlaintextSize + 16;
	pEncrypted = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwEncryptedSize);
	if (!pEncrypted) {
		printf("[!] HeapAlloc failed\n");
		CryptDestroyKey(hKey);
		CryptDestroyHash(hHash);
		CryptReleaseContext(hProv, 0);
		return NULL;
	}

	memcpy(pEncrypted, pPlaintext, sPlaintextSize);
	dwEncryptedSize = (DWORD)sPlaintextSize;

	if (!CryptEncrypt(hKey, 0, TRUE, 0, pEncrypted, &dwEncryptedSize, dwEncryptedSize + 16)) {
		printf("[!] CryptEncrypt failed: %d\n", GetLastError());
		HeapFree(GetProcessHeap(), 0, pEncrypted);
		CryptDestroyKey(hKey);
		CryptDestroyHash(hHash);
		CryptReleaseContext(hProv, 0);
		return NULL;
	}

	*pEncryptedSize = dwEncryptedSize;
	CryptDestroyKey(hKey);
	CryptDestroyHash(hHash);
	CryptReleaseContext(hProv, 0);

	printf("[+] Encryption successful: %zu bytes\n", dwEncryptedSize);
	return pEncrypted;
}

int main(int argc, char* argv[]) {
	WCHAR szBeaconPath[MAX_PATH] = { 0 };
	WCHAR szOutputPath[MAX_PATH] = { 0 };
	char szEncryptionKey[256] = { 0 };
	char* pBeaconPathArg = NULL;
	char* pKeyArg = NULL;
	PBYTE pBeaconFile = NULL;
	PBYTE pEncryptedData = NULL;
	SIZE_T sBeaconSize = 0;
	SIZE_T sEncryptedSize = 0;
	HANDLE hOutputFile = INVALID_HANDLE_VALUE;
	DWORD dwBytesWritten = 0;

	printf("=== AES-256 Encryptor ===\n\n");

	// Parse arguments - support both formats:
	// Format 1: encryptor.exe beacon.exe encryption_key
	// Format 2: encryptor.exe -file beacon.exe -key encryption_key
	if (argc < 3) {
		printf("Usage:\n");
		printf("  Format 1: encryptor.exe <beacon.exe> <encryption_key>\n");
		printf("  Format 2: encryptor.exe -file <beacon.exe> -key <encryption_key>\n\n");
		printf("Examples:\n");
		printf("  encryptor.exe beacon.exe MySecret123\n");
		printf("  encryptor.exe -file beacon.exe -key MySecret123\n\n");
		printf("Output: beacon.exe.enc\n\n");
		return -1;
	}

	// Parse arguments
	if (strcmp(argv[1], "-file") == 0 && argc >= 5) {
		// Format 2: -file beacon.exe -key encryption_key
		pBeaconPathArg = argv[2];
		if (strcmp(argv[3], "-key") == 0) {
			pKeyArg = argv[4];
		}
		else {
			printf("[!] Invalid argument format. Use: -file <path> -key <key>\n");
			return -1;
		}
	}
	else if (argv[1][0] != '-') {
		// Format 1: beacon.exe encryption_key
		pBeaconPathArg = argv[1];
		pKeyArg = argv[2];
	}
	else {
		printf("[!] Invalid arguments. Use -file <path> -key <key> or <path> <key>\n");
		return -1;
	}

	if (!pBeaconPathArg || !pKeyArg) {
		printf("[!] Missing beacon path or encryption key\n");
		return -1;
	}

	mbstowcs_s(NULL, szBeaconPath, MAX_PATH, pBeaconPathArg, MAX_PATH - 1);
	strcpy_s(szEncryptionKey, sizeof(szEncryptionKey), pKeyArg);

	printf("[*] Reading beacon file...\n");
	pBeaconFile = ReadFileToBuffer(szBeaconPath, &sBeaconSize);
	if (!pBeaconFile) {
		printf("[!] Failed to read beacon\n");
		return -1;
	}

	printf("[*] Encrypting with AES-256...\n");
	pEncryptedData = AesEncrypt(pBeaconFile, sBeaconSize, (PBYTE)szEncryptionKey, strlen(szEncryptionKey), &sEncryptedSize);
	if (!pEncryptedData) {
		printf("[!] Encryption failed\n");
		HeapFree(GetProcessHeap(), 0, pBeaconFile);
		return -1;
	}

	// Create output filename: beacon.exe.enc
	wcscpy_s(szOutputPath, MAX_PATH, szBeaconPath);
	wcscat_s(szOutputPath, MAX_PATH, L".enc");

	// Write encrypted data to file
	printf("[*] Writing encrypted payload to file...\n");
	hOutputFile = CreateFileW(szOutputPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hOutputFile == INVALID_HANDLE_VALUE) {
		printf("[!] CreateFileW failed: %d\n", GetLastError());
		HeapFree(GetProcessHeap(), 0, pBeaconFile);
		HeapFree(GetProcessHeap(), 0, pEncryptedData);
		return -1;
	}

	if (!WriteFile(hOutputFile, pEncryptedData, (DWORD)sEncryptedSize, &dwBytesWritten, NULL) || dwBytesWritten != sEncryptedSize) {
		printf("[!] WriteFile failed: %d\n", GetLastError());
		CloseHandle(hOutputFile);
		HeapFree(GetProcessHeap(), 0, pBeaconFile);
		HeapFree(GetProcessHeap(), 0, pEncryptedData);
		return -1;
	}

	CloseHandle(hOutputFile);

	printf("\n[+] ========== ENCRYPTION SUCCESSFUL ==========\n");
	printf("[+] Encryption key: %s\n", szEncryptionKey);
	printf("[+] Original size: %zu bytes\n", sBeaconSize);
	printf("[+] Encrypted size: %zu bytes\n", sEncryptedSize);
	printf("[+] Output file: ");
	printf("%S\n", szOutputPath);
	printf("[+] ============================================\n\n");
	printf("[*] Next steps:\n");
	printf("    1. Add %S to .rsrc section using Resource Hacker\n", szOutputPath);
	printf("    2. Resource Type: RCDATA (IDR_RCDATA1), ID: 101\n");
	printf("    3. Run loader: loader.exe -key \"%s\"\n\n", szEncryptionKey);

	HeapFree(GetProcessHeap(), 0, pBeaconFile);
	HeapFree(GetProcessHeap(), 0, pEncryptedData);

	return 0;
}
This post is licensed under CC BY 4.0 by the author.