#pragma once
#include "../../Include/Winheaders.h"
#include "../../PE/PEImage.h"
#include "../../Include/Types.h"
#include "../../Include/NativeStructures.h"
#include "../../Include/Macro.h"
#include "../../Include/CallResult.h"
namespace blackbone
{
enum LdrRefFlags
{
Ldr_None = 0x00, // Do not create any reference
Ldr_ModList = 0x01, // Add to module list - LdrpModuleIndex( win8 only ), InMemoryOrderModuleList( win7 only )
Ldr_HashTable = 0x02, // Add to LdrpHashTable
Ldr_ThdCall = 0x04, // Add to thread callback list (dllmain will be called with THREAD_ATTACH/DETACH reasons)
Ldr_All = 0xFF, // Add to everything
Ldr_Ignore = 0xDE // Only valid in mod callback, mod callback value will be ignored
};
ENUM_OPS( LdrRefFlags )
struct NtLdrEntry : ModuleData
{
LdrRefFlags flags = Ldr_None;
ptr_t entryPoint = 0;
ULONG hash = 0;
bool safeSEH = false;
};
class NtLdr
{
public:
BLACKBONE_API NtLdr( class Process& proc );
BLACKBONE_API ~NtLdr( void );
///
/// Initialize some loader stuff
///
/// Target module type
/// true on success
BLACKBONE_API bool Init( eModType initFor = mt_default );
///
/// Add module to some loader structures
/// (LdrpHashTable, LdrpModuleIndex( win8 only ), InMemoryOrderModuleList( win7 only ))
///
/// Module data
/// true on success
BLACKBONE_API bool CreateNTReference( NtLdrEntry& mod );
///
/// Create thread static TLS array
///
/// Module data
/// TLS directory of target image
/// Status code
BLACKBONE_API NTSTATUS AddStaticTLSEntry( NtLdrEntry& mod, ptr_t tlsPtr );
///
/// Create module record in LdrpInvertedFunctionTable
/// Used to create fake SAFESEH entries
///
/// Module data
/// true on success
BLACKBONE_API bool InsertInvertedFunctionTable( NtLdrEntry& mod );
///
/// Free static TLS
///
/// Target module
/// Don't create new threads during remote call
/// Status code
BLACKBONE_API NTSTATUS UnloadTLS( const NtLdrEntry& mod, bool noThread = false );
///
/// Unlink module from Ntdll loader
///
/// Module data
/// Don't create new threads during unlink
/// true on success
BLACKBONE_API bool Unlink( const ModuleData& mod, bool noThread = false );
private:
///
/// Find LdrpHashTable[] variable
///
/// true on success
template
bool FindLdrpHashTable();
///
/// Find LdrpModuleIndex variable under win8
///
/// true on success
template
bool FindLdrpModuleIndexBase();
///
/// Find Loader heap base
///
/// true on success
template
bool FindLdrHeap();
///
/// Initialize OS-specific module entry
///
/// Module data
/// Pointer to created entry
template
ptr_t InitBaseNode( NtLdrEntry& mod );
///
/// Initialize OS-specific module entry
///
/// Module data
/// Pointer to created entry
template
ptr_t InitW8Node( NtLdrEntry& mod );
///
/// Initialize OS-specific module entry
///
/// Module data
/// Pointer to created entry
template
ptr_t InitW7Node( NtLdrEntry& mod );
///
/// Insert entry into win8 module graph
///
/// Node to insert
/// Module data
template
void InsertTreeNode( ptr_t nodePtr, const NtLdrEntry& mod );
///
/// Insert entry into LdrpHashTable[]
///
/// Link of entry to be inserted
/// Module hash
template
void InsertHashNode( ptr_t pNodeLink, ULONG hash );
///
/// Insert entry into InLoadOrderModuleList and InMemoryOrderModuleList
///
/// InMemoryOrderModuleList link of entry to be inserted
/// InLoadOrderModuleList link of entry to be inserted
template
void InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink );
///
/// Insert entry into standard double linked list
///
/// List head pointer
/// Entry list link to be inserted
template
void InsertTailList( ptr_t ListHead, ptr_t Entry );
///
/// Hash image name
///
/// Iamge name
/// Hash
ULONG HashString( const std::wstring& str );
///
/// Allocate memory from heap if possible
///
/// Module type
/// Size to allocate
/// Allocated address
call_result_t AllocateInHeap( eModType mt, size_t size );
///
/// Get module native node ptr or create new
///
/// node pointer (if nullptr - new dummy node is allocated)
/// Module base address
/// Node address
template
ptr_t SetNode( ptr_t ptr, Module pModule );
///
/// Unlink module from PEB_LDR_DATA
///
/// Module data
/// Address of removed record
template
ptr_t UnlinkFromLdr( const ModuleData& mod );
///
/// Finds LDR entry for module
///
/// Target module base
/// Found entry
/// Found LDR entry address
template
ptr_t FindLdrEntry( module_t moduleBase, _LDR_DATA_TABLE_ENTRY_BASE_T* found = nullptr );
///
/// Remove record from LIST_ENTRY structure
///
/// Entry link
template
void UnlinkListEntry( ptr_t pListLink );
///
/// Unlink from module graph
///
/// Module data
/// Module LDR entry
/// Don't create new threads during unlink
/// Address of removed record
template
ptr_t UnlinkTreeNode( const ModuleData& mod, ptr_t ldrEntry, bool noThread = false );
NtLdr( const NtLdr& ) = delete;
NtLdr& operator =(const NtLdr&) = delete;
private:
class Process& _process; // Process memory routines
ptr_t _LdrpHashTable = 0; // LdrpHashTable address
ptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address
ptr_t _LdrHeapBase = 0; // Loader heap base address
eModType _initializedFor = mt_unknown; // Loader initialization target
std::map _nodeMap; // Allocated native structures
};
}