
Bibliothèque C++17 header-only pour le développement Windows furtif : hashage d'API au moment de la compilation, déhook de DLL, effacement des points d'arrêt matériels, suppression du VEH et suppression des callbacks de notification DLL pour contourner les hooks EDR.
Ceci fait suite à mon projet original WTSRM et à la présentation correspondante.
Ce projet a été réécrit afin d'utiliser C++17 pour créer un template qui nous permet de modifier la fonctionnalité requise au moment de la compilation en toute simplicité ! Il est implémenté comme un fichier header-only, de sorte que vous pouvez facilement l'ajouter à vos propres projets.
Certaines des fonctionnalités actuellement implémentées incluent :
Nous pouvons configurer ce comportement comme suit
#define HASHING_ALGORITHM hash_string_fnv1a // constexpr algorithm
namespace config
{
...
//
// configure behaviour
//
inline constexpr unsigned unhooking = system32 | write_process_memory;
inline constexpr auto work_item_load_library = true; // use a work item for LL
//
// configure evasive features
//
inline constexpr auto clear_and_restore_veh = true; // clear and restore veh
inline constexpr auto unregister_dll_notifs = true; // LdrRegisterDllNotification
inline constexpr auto clear_thread_hwbps = true; // clear the hwbps
}
Comme nous utilisons constexpr, nous ne payons pas pour les fonctionnalités que nous n'utilisons pas, car elles sont du code mort et sont supprimées lors de l'optimisation.
Pour importer des DLL, nous devons d'abord créer le hachage à l'aide de la macro DLL_HASH
DLL_HASH(DBGHELP, L"DBGHELP.DLL")
Nous devons ensuite l'ajouter au module_address_table qui agit comme notre IAT interne. La constante hash_ est créée par la macro DLL_HASH. Pour les DLL non courantes qui ne sont pas toujours chargées, nous devons spécifier leur nom afin de pouvoir les charger.
inline addr_struct<decltype(HASHING_ALGORITHM(TOKENIZEA(T))), wchar_t> module_address_table[] =
{
{hash_NTDLL, nullptr,},
{hash_KERNEL32, nullptr,},
{hash_DBGHELP, nullptr, L"DBGHELP.DLL"}
};
Pour importer des fonctions, nous devons d'abord créer le hachage du nom de fonction et le typedef à l'aide de la macro HASH_FUNC
HASH_FUNC(NtUnmapViewOfSection, NTSTATUS, HANDLE, PVOID)
Le premier paramètre est le nom de la fonction, le suivant est le type de retour, puis les arguments de la fonction. Nous devons ensuite l'ajouter à notre api_address_table, qui contiendra les adresses actuelles des fonctions.
inline addr_struct<decltype(HASHING_ALGORITHM(TOKENIZEA(T))), void> api_address_table[] =
{
{hash_GetProcAddress, nullptr},
{hash_NtUnmapViewOfSection, nullptr},
Si vous n'ajoutez pas cette fonction à ce tableau, le programme ne plantera pas, mais retournera -1 afin d'accroître la stabilité.
Pour utiliser une API, utilisez la macro API()() comme illustré ci-dessous
API(NtWaitForSingleObject)(NtCurrentProcess(), FALSE, &timeout);
Pour ajouter votre propre fonction de hachage d'API, vous devez utiliser ce template afin qu'elle fonctionne avec les types requis.
template <typename T>
constexpr auto hash_string_(const T* buffer)
{
TRIVIAL_TYPE_CHECK()
}
Merci à ces personnes, sans ordre particulier, pour leurs idées et contributions @peterwintrsmith @modexpblog @jonaslyk @JustasMasiulis