Created
January 17, 2024 17:00
-
-
Save WKL-Sec/39f44f202db78e2121ca75c017b109b8 to your computer and use it in GitHub Desktop.
This C++ code example is part of the White Knight Labs Offensive Development Course materials. A straightforward C++ code snippet demonstrating how to prevent DLL sideloading by validating the calling executable. It uses a whitelist approach to ensure only specified executables can load the DLL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <string> | |
#include <vector> | |
#include <algorithm> | |
// White Knight Labs - Offensive Development Course | |
// DLL Guardrails Example | |
// This function extracts the file name from a given path | |
// It is used later to determine the executable name loading the DLL. | |
std::string ExtractFileName(const std::string& path) { | |
size_t lastSlashPos = path.find_last_of("\\/"); | |
return lastSlashPos != std::string::npos ? path.substr(lastSlashPos + 1) : path; | |
} | |
// Entry point for the DLL | |
BOOL APIENTRY DllMain(HMODULE hModule, | |
DWORD ul_reason_for_call, | |
LPVOID lpReserved) { | |
CHAR processPath[MAX_PATH] = { 0 }; | |
// List of executables allowed to load this DLL | |
std::vector<std::string> allowedExecutables = { | |
"Word.exe", // Example allowed executable | |
"Chrome.exe", // Another example allowed executable | |
"Caller.exe" // Placeholder for additional executables | |
// Add any other executable names as needed | |
}; | |
// Retrieve the full path of the process trying to load the DLL | |
GetModuleFileNameA(NULL, processPath, MAX_PATH); | |
std::string executableName = ExtractFileName(processPath); | |
// Determine the reason for calling DllMain and act accordingly | |
switch (ul_reason_for_call) { | |
case DLL_PROCESS_ATTACH: | |
// Check if the executable is not in the list of allowed executables | |
if (std::find(allowedExecutables.begin(), allowedExecutables.end(), executableName) == allowedExecutables.end()) { | |
// Prevent DLL from being loaded by an unknown or unauthorized executable | |
return FALSE; | |
} | |
// Break is important to prevent fall-through to other cases | |
break; | |
case DLL_THREAD_ATTACH: | |
// Code to run when a new thread is created within the process | |
break; | |
case DLL_THREAD_DETACH: | |
// Code to run when a thread within the process ends cleanly | |
break; | |
case DLL_PROCESS_DETACH: | |
// Code to run when the DLL is unloaded from a process | |
break; | |
} | |
// Allow the DLL to load if no conditions are violated | |
return TRUE; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment