2022-04-10 19:59:34 +02:00
//===========================================================================//
//
// Purpose: Implementation of the CModule class.
//
//===========================================================================//
2023-05-06 22:59:01 +02:00
# include "tier0/memaddr.h"
# include "tier0/sigcache.h"
2023-06-12 18:40:16 +02:00
# include "windows/tebpeb64.h"
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
// Purpose: constructor
2023-06-12 18:40:16 +02:00
// Input : *szModuleName -
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CModule : : CModule ( const char * szModuleName )
: m_ModuleName ( szModuleName )
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
m_pModuleBase = reinterpret_cast < uintptr_t > ( GetModuleHandleA ( szModuleName ) ) ;
2022-04-10 19:59:34 +02:00
2023-01-31 23:52:11 +01:00
Init ( ) ;
LoadSections ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: constructor
2023-06-12 18:40:16 +02:00
// Input : *szModuleName -
// nModuleBase -
2023-01-31 23:52:11 +01:00
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CModule : : CModule ( const char * szModuleName , const uintptr_t nModuleBase )
: m_ModuleName ( szModuleName )
2023-04-02 12:09:43 +02:00
, m_pModuleBase ( nModuleBase )
2023-01-31 23:52:11 +01:00
{
Init ( ) ;
LoadSections ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: initializes module descriptors
//-----------------------------------------------------------------------------
void CModule : : Init ( )
{
2022-04-10 19:59:34 +02:00
m_pDOSHeader = reinterpret_cast < IMAGE_DOS_HEADER * > ( m_pModuleBase ) ;
m_pNTHeaders = reinterpret_cast < IMAGE_NT_HEADERS64 * > ( m_pModuleBase + m_pDOSHeader - > e_lfanew ) ;
2023-01-31 23:52:11 +01:00
m_nModuleSize = static_cast < size_t > ( m_pNTHeaders - > OptionalHeader . SizeOfImage ) ;
2022-04-10 19:59:34 +02:00
const IMAGE_SECTION_HEADER * hSection = IMAGE_FIRST_SECTION ( m_pNTHeaders ) ; // Get first image section.
for ( WORD i = 0 ; i < m_pNTHeaders - > FileHeader . NumberOfSections ; i + + ) // Loop through the sections.
{
const IMAGE_SECTION_HEADER & hCurrentSection = hSection [ i ] ; // Get current section.
2023-06-12 18:40:16 +02:00
m_ModuleSections . push_back ( ModuleSections_t ( reinterpret_cast < const char * > ( hCurrentSection . Name ) ,
2022-04-10 19:59:34 +02:00
static_cast < uintptr_t > ( m_pModuleBase + hCurrentSection . VirtualAddress ) , hCurrentSection . SizeOfRawData ) ) ; // Push back a struct with the section data.
}
2023-01-31 23:52:11 +01:00
}
2022-06-13 23:34:06 +02:00
2023-01-31 23:52:11 +01:00
//-----------------------------------------------------------------------------
// Purpose: initializes the default executable segments
//-----------------------------------------------------------------------------
void CModule : : LoadSections ( )
{
2022-06-13 23:34:06 +02:00
m_ExecutableCode = GetSectionByName ( " .text " ) ;
m_ExceptionTable = GetSectionByName ( " .pdata " ) ;
m_RunTimeData = GetSectionByName ( " .data " ) ;
m_ReadOnlyData = GetSectionByName ( " .rdata " ) ;
2022-04-10 19:59:34 +02:00
}
2022-12-03 00:08:48 +01:00
# ifndef PLUGINSDK
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
// Purpose: find array of bytes in process memory using SIMD instructions
2023-06-12 18:40:16 +02:00
// Input : *pPattern -
// *szMask -
// *moduleSection -
// nOccurrence -
2022-04-10 19:59:34 +02:00
// Output : CMemory
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : FindPatternSIMD ( const uint8_t * pPattern , const char * szMask ,
const ModuleSections_t * moduleSection , const size_t nOccurrence ) const
2022-04-10 19:59:34 +02:00
{
2022-06-13 23:34:06 +02:00
if ( ! m_ExecutableCode . IsSectionValid ( ) )
2022-04-10 19:59:34 +02:00
return CMemory ( ) ;
2022-12-20 23:38:45 +01:00
const bool bSectionValid = moduleSection ? moduleSection - > IsSectionValid ( ) : false ;
2022-07-20 18:03:35 +02:00
2022-12-20 23:38:45 +01:00
const uintptr_t nBase = bSectionValid ? moduleSection - > m_pSectionBase : m_ExecutableCode . m_pSectionBase ;
const uintptr_t nSize = bSectionValid ? moduleSection - > m_nSectionSize : m_ExecutableCode . m_nSectionSize ;
2022-04-10 19:59:34 +02:00
2022-12-01 22:47:39 +01:00
const size_t nMaskLen = strlen ( szMask ) ;
2022-04-10 19:59:34 +02:00
const uint8_t * pData = reinterpret_cast < uint8_t * > ( nBase ) ;
2022-12-05 00:57:48 +01:00
const uint8_t * pEnd = pData + nSize - nMaskLen ;
2022-04-10 19:59:34 +02:00
2023-04-02 12:09:43 +02:00
size_t nOccurrenceCount = 0 ;
2022-04-10 19:59:34 +02:00
int nMasks [ 64 ] ; // 64*16 = enough masks for 1024 bytes.
2022-12-01 22:47:39 +01:00
const int iNumMasks = static_cast < int > ( ceil ( static_cast < float > ( nMaskLen ) / 16.f ) ) ;
2022-04-10 19:59:34 +02:00
memset ( nMasks , ' \0 ' , iNumMasks * sizeof ( int ) ) ;
for ( intptr_t i = 0 ; i < iNumMasks ; + + i )
{
for ( intptr_t j = strnlen ( szMask + i * 16 , 16 ) - 1 ; j > = 0 ; - - j )
{
if ( szMask [ i * 16 + j ] = = ' x ' )
{
2022-11-24 15:41:52 +01:00
_bittestandset ( reinterpret_cast < LONG * > ( & nMasks [ i ] ) , static_cast < LONG > ( j ) ) ;
2022-04-10 19:59:34 +02:00
}
}
}
2023-06-12 18:40:16 +02:00
const __m128i xmm1 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( pPattern ) ) ;
2022-04-10 19:59:34 +02:00
__m128i xmm2 , xmm3 , msks ;
for ( ; pData ! = pEnd ; _mm_prefetch ( reinterpret_cast < const char * > ( + + pData + 64 ) , _MM_HINT_NTA ) )
{
2023-06-12 18:40:16 +02:00
if ( pPattern [ 0 ] = = pData [ 0 ] )
2022-04-10 19:59:34 +02:00
{
xmm2 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( pData ) ) ;
msks = _mm_cmpeq_epi8 ( xmm1 , xmm2 ) ;
if ( ( _mm_movemask_epi8 ( msks ) & nMasks [ 0 ] ) = = nMasks [ 0 ] )
{
for ( uintptr_t i = 1 ; i < static_cast < uintptr_t > ( iNumMasks ) ; + + i )
{
xmm2 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( ( pData + i * 16 ) ) ) ;
2023-06-12 18:40:16 +02:00
xmm3 = _mm_loadu_si128 ( reinterpret_cast < const __m128i * > ( ( pPattern + i * 16 ) ) ) ;
2022-04-10 19:59:34 +02:00
msks = _mm_cmpeq_epi8 ( xmm2 , xmm3 ) ;
if ( ( _mm_movemask_epi8 ( msks ) & nMasks [ i ] ) = = nMasks [ i ] )
{
if ( ( i + 1 ) = = iNumMasks )
{
2022-09-09 19:47:31 +02:00
if ( nOccurrenceCount = = nOccurrence )
2022-08-15 21:05:42 +02:00
{
return static_cast < CMemory > ( const_cast < uint8_t * > ( pData ) ) ;
}
2022-09-09 19:47:31 +02:00
nOccurrenceCount + + ;
2022-04-10 19:59:34 +02:00
}
}
else
{
goto cont ;
}
}
2022-09-09 19:47:31 +02:00
if ( nOccurrenceCount = = nOccurrence )
2022-08-15 21:05:42 +02:00
{
return static_cast < CMemory > ( ( & * ( const_cast < uint8_t * > ( pData ) ) ) ) ;
}
2022-09-09 19:47:31 +02:00
nOccurrenceCount + + ;
2022-04-10 19:59:34 +02:00
}
} cont : ;
}
return CMemory ( ) ;
}
2022-06-25 00:08:02 +02:00
//-----------------------------------------------------------------------------
2022-12-02 10:37:41 +01:00
// Purpose: find a string pattern in process memory using SIMD instructions
2023-06-12 18:40:16 +02:00
// Input : *szPattern -
// *moduleSection -
2022-06-25 00:08:02 +02:00
// Output : CMemory
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : FindPatternSIMD ( const char * szPattern , const ModuleSections_t * moduleSection ) const
2022-06-25 00:08:02 +02:00
{
2022-12-02 10:37:41 +01:00
uint64_t nRVA ;
2023-06-12 18:40:16 +02:00
if ( g_SigCache . FindEntry ( szPattern , nRVA ) )
2022-12-02 00:30:49 +01:00
{
2022-12-02 10:37:41 +01:00
return CMemory ( nRVA + GetModuleBase ( ) ) ;
2022-12-02 00:30:49 +01:00
}
2023-06-12 18:40:16 +02:00
const pair < vector < uint8_t > , string > patternInfo = PatternToMaskedBytes ( szPattern ) ;
2022-12-05 00:57:48 +01:00
const CMemory memory = FindPatternSIMD ( patternInfo . first . data ( ) , patternInfo . second . c_str ( ) , moduleSection ) ;
2022-12-02 00:30:49 +01:00
2023-06-12 18:40:16 +02:00
g_SigCache . AddEntry ( szPattern , GetRVA ( memory . GetPtr ( ) ) ) ;
2022-12-02 00:30:49 +01:00
return memory ;
2022-06-25 00:08:02 +02:00
}
2023-06-12 18:40:16 +02:00
//-----------------------------------------------------------------------------
// Purpose: find address of reference to string constant in executable memory
// Input : *szString -
// bNullTerminator -
// Output : CMemory
//-----------------------------------------------------------------------------
CMemory CModule : : FindString ( const char * szString , const ptrdiff_t nOccurrence , bool bNullTerminator ) const
{
if ( ! m_ExecutableCode . IsSectionValid ( ) )
return CMemory ( ) ;
uint64_t nRVA ;
string svPackedString = szString + std : : to_string ( nOccurrence ) ;
if ( g_SigCache . FindEntry ( svPackedString . c_str ( ) , nRVA ) )
{
return CMemory ( nRVA + GetModuleBase ( ) ) ;
}
const CMemory stringAddress = FindStringReadOnly ( szString , bNullTerminator ) ; // Get Address for the string in the .rdata section.
if ( ! stringAddress )
return CMemory ( ) ;
uint8_t * pLatestOccurrence = nullptr ;
uint8_t * pTextStart = reinterpret_cast < uint8_t * > ( m_ExecutableCode . m_pSectionBase ) ; // Get the start of the .text section.
ptrdiff_t dOccurrencesFound = 0 ;
CMemory resultAddress ;
for ( size_t i = 0ull ; i < m_ExecutableCode . m_nSectionSize - 0x5 ; i + + )
{
byte byte = pTextStart [ i ] ;
if ( byte = = LEA )
{
const CMemory skipOpCode = CMemory ( reinterpret_cast < uintptr_t > ( & pTextStart [ i ] ) ) . OffsetSelf ( 0x2 ) ; // Skip next 2 opcodes, those being the instruction and the register.
const int32_t relativeAddress = skipOpCode . GetValue < int32_t > ( ) ; // Get 4-byte long string relative Address
const uintptr_t nextInstruction = skipOpCode . Offset ( 0x4 ) . GetPtr ( ) ; // Get location of next instruction.
const CMemory potentialLocation = CMemory ( nextInstruction + relativeAddress ) ; // Get potential string location.
if ( potentialLocation = = stringAddress )
{
dOccurrencesFound + + ;
if ( nOccurrence = = dOccurrencesFound )
{
resultAddress = CMemory ( & pTextStart [ i ] ) ;
g_SigCache . AddEntry ( svPackedString . c_str ( ) , GetRVA ( resultAddress . GetPtr ( ) ) ) ;
return resultAddress ;
}
pLatestOccurrence = & pTextStart [ i ] ; // Stash latest occurrence.
}
}
}
resultAddress = CMemory ( pLatestOccurrence ) ;
g_SigCache . AddEntry ( svPackedString . c_str ( ) , GetRVA ( resultAddress . GetPtr ( ) ) ) ;
return resultAddress ;
}
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
// Purpose: find address of input string constant in read only memory
2023-06-12 18:40:16 +02:00
// Input : *szString -
2022-04-10 19:59:34 +02:00
// bNullTerminator -
// Output : CMemory
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : FindStringReadOnly ( const char * szString , bool bNullTerminator ) const
2022-04-10 19:59:34 +02:00
{
2022-06-13 23:34:06 +02:00
if ( ! m_ReadOnlyData . IsSectionValid ( ) )
2022-04-10 19:59:34 +02:00
return CMemory ( ) ;
2022-12-02 11:10:53 +01:00
uint64_t nRVA ;
2023-06-12 18:40:16 +02:00
if ( g_SigCache . FindEntry ( szString , nRVA ) )
2022-12-02 11:10:53 +01:00
{
return CMemory ( nRVA + GetModuleBase ( ) ) ;
}
2023-06-12 18:40:16 +02:00
const vector < int > vBytes = StringToBytes ( szString , bNullTerminator ) ; // Convert our string to a byte array.
2023-03-20 00:21:03 +01:00
const pair < size_t , const int * > bytesInfo = std : : make_pair < size_t , const int * > ( vBytes . size ( ) , vBytes . data ( ) ) ; // Get the size and data of our bytes.
2022-04-10 19:59:34 +02:00
2022-12-05 00:57:48 +01:00
const uint8_t * pBase = reinterpret_cast < uint8_t * > ( m_ReadOnlyData . m_pSectionBase ) ; // Get start of .rdata section.
2022-04-10 19:59:34 +02:00
2022-06-13 23:34:06 +02:00
for ( size_t i = 0ull ; i < m_ReadOnlyData . m_nSectionSize - bytesInfo . first ; i + + )
2022-04-10 19:59:34 +02:00
{
bool bFound = true ;
// If either the current byte equals to the byte in our pattern or our current byte in the pattern is a wildcard
// our if clause will be false.
for ( size_t j = 0ull ; j < bytesInfo . first ; j + + )
{
if ( pBase [ i + j ] ! = bytesInfo . second [ j ] & & bytesInfo . second [ j ] ! = - 1 )
{
bFound = false ;
break ;
}
}
if ( bFound )
{
2022-12-02 11:10:53 +01:00
CMemory result = CMemory ( & pBase [ i ] ) ;
2023-06-12 18:40:16 +02:00
g_SigCache . AddEntry ( szString , GetRVA ( result . GetPtr ( ) ) ) ;
2022-12-02 11:10:53 +01:00
return result ;
2022-04-10 19:59:34 +02:00
}
}
return CMemory ( ) ;
}
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
// Purpose: find 'free' page in r/w/x sections
// Input : nSize -
2022-04-10 19:59:34 +02:00
// Output : CMemory
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : FindFreeDataPage ( const size_t nSize ) const
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
auto checkDataSection = [ ] ( const void * address , const std : : size_t size )
2022-12-02 10:37:41 +01:00
{
2023-06-12 18:40:16 +02:00
MEMORY_BASIC_INFORMATION membInfo = { 0 } ;
2022-12-02 10:37:41 +01:00
2023-06-12 18:40:16 +02:00
VirtualQuery ( address , & membInfo , sizeof ( membInfo ) ) ;
2022-08-15 21:05:42 +02:00
2023-06-12 18:40:16 +02:00
if ( membInfo . AllocationBase & & membInfo . BaseAddress & & membInfo . State = = MEM_COMMIT & & ! ( membInfo . Protect & PAGE_GUARD ) & & membInfo . Protect ! = PAGE_NOACCESS )
{
if ( ( membInfo . Protect & ( PAGE_EXECUTE_READWRITE | PAGE_READWRITE ) ) & & membInfo . RegionSize > = size )
{
return ( ( membInfo . Protect & ( PAGE_EXECUTE_READWRITE | PAGE_READWRITE ) ) & & membInfo . RegionSize > = size ) ? true : false ;
}
}
return false ;
} ;
2022-04-10 19:59:34 +02:00
2023-06-12 18:40:16 +02:00
// This is very unstable, this doesn't check for the actual 'page' sizes.
// Also can be optimized to search per 'section'.
const uintptr_t endOfModule = m_pModuleBase + m_pNTHeaders - > OptionalHeader . SizeOfImage - sizeof ( uintptr_t ) ;
for ( uintptr_t currAddr = endOfModule ; m_pModuleBase < currAddr ; currAddr - = sizeof ( uintptr_t ) )
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
if ( * reinterpret_cast < uintptr_t * > ( currAddr ) = = 0 & & checkDataSection ( reinterpret_cast < void * > ( currAddr ) , nSize ) )
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
bool bIsGoodPage = true ;
uint32_t nPageCount = 0 ;
2022-04-10 19:59:34 +02:00
2023-06-12 18:40:16 +02:00
for ( ; nPageCount < nSize & & bIsGoodPage ; nPageCount + = sizeof ( uintptr_t ) )
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
const uintptr_t pageData = * reinterpret_cast < std : : uintptr_t * > ( currAddr + nPageCount ) ;
if ( pageData ! = 0 )
bIsGoodPage = false ;
2022-04-10 19:59:34 +02:00
}
2023-06-12 18:40:16 +02:00
if ( bIsGoodPage & & nPageCount > = nSize )
return currAddr ;
2022-04-10 19:59:34 +02:00
}
}
2022-12-02 10:37:41 +01:00
2023-06-12 18:40:16 +02:00
return CMemory ( ) ;
2022-04-10 19:59:34 +02:00
}
2022-12-03 00:08:48 +01:00
//-----------------------------------------------------------------------------
// Purpose: get address of a virtual method table by rtti type descriptor name.
2023-06-12 18:40:16 +02:00
// Input : *szTableName -
// nRefIndex -
2023-04-02 12:09:43 +02:00
// Output : address of virtual method table, null if not found.
2022-12-03 00:08:48 +01:00
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : GetVirtualMethodTable ( const char * szTableName , const size_t nRefIndex )
2022-12-03 00:08:48 +01:00
{
uint64_t nRVA ; // Packed together as we can have multiple VFTable searches, but with different ref indexes.
2023-06-12 18:40:16 +02:00
string svPackedTableName = szTableName + std : : to_string ( nRefIndex ) ;
2022-12-03 00:08:48 +01:00
2023-06-12 18:40:16 +02:00
if ( g_SigCache . FindEntry ( svPackedTableName . c_str ( ) , nRVA ) )
2022-12-03 00:08:48 +01:00
{
return CMemory ( nRVA + GetModuleBase ( ) ) ;
}
2023-06-12 18:40:16 +02:00
ModuleSections_t moduleSection ( " .data " , m_RunTimeData . m_pSectionBase , m_RunTimeData . m_nSectionSize ) ;
2022-12-20 23:38:45 +01:00
2023-06-12 18:40:16 +02:00
const auto tableNameInfo = StringToMaskedBytes ( szTableName , false ) ;
2022-12-20 23:38:45 +01:00
CMemory rttiTypeDescriptor = FindPatternSIMD ( tableNameInfo . first . data ( ) , tableNameInfo . second . c_str ( ) , & moduleSection ) . OffsetSelf ( - 0x10 ) ;
2022-12-03 00:08:48 +01:00
if ( ! rttiTypeDescriptor )
return CMemory ( ) ;
uintptr_t scanStart = m_ReadOnlyData . m_pSectionBase ; // Get the start address of our scan.
const uintptr_t scanEnd = ( m_ReadOnlyData . m_pSectionBase + m_ReadOnlyData . m_nSectionSize ) - 0x4 ; // Calculate the end of our scan.
const uintptr_t rttiTDRva = rttiTypeDescriptor . GetPtr ( ) - m_pModuleBase ; // The RTTI gets referenced by a 4-Byte RVA address. We need to scan for that address.
while ( scanStart < scanEnd )
{
2022-12-20 23:38:45 +01:00
moduleSection = { " .rdata " , scanStart , m_ReadOnlyData . m_nSectionSize } ;
CMemory reference = FindPatternSIMD ( reinterpret_cast < rsig_t > ( & rttiTDRva ) , " xxxx " , & moduleSection , nRefIndex ) ;
2022-12-03 00:08:48 +01:00
if ( ! reference )
break ;
CMemory referenceOffset = reference . Offset ( - 0xC ) ;
if ( referenceOffset . GetValue < int32_t > ( ) ! = 1 ) // Check if we got a RTTI Object Locator for this reference by checking if -0xC is 1, which is the 'signature' field which is always 1 on x64.
{
scanStart = reference . Offset ( 0x4 ) . GetPtr ( ) ; // Set location to current reference + 0x4 so we avoid pushing it back again into the vector.
continue ;
}
2022-12-20 23:38:45 +01:00
moduleSection = { " .rdata " , m_ReadOnlyData . m_pSectionBase , m_ReadOnlyData . m_nSectionSize } ;
CMemory vfTable = FindPatternSIMD ( reinterpret_cast < rsig_t > ( & referenceOffset ) , " xxxxxxxx " , & moduleSection ) . OffsetSelf ( 0x8 ) ;
2023-06-12 18:40:16 +02:00
g_SigCache . AddEntry ( svPackedTableName . c_str ( ) , GetRVA ( vfTable . GetPtr ( ) ) ) ;
2022-12-03 00:08:48 +01:00
return vfTable ;
}
return CMemory ( ) ;
2022-04-10 19:59:34 +02:00
}
2022-12-03 00:08:48 +01:00
# endif // !PLUGINSDK
2022-04-10 19:59:34 +02:00
2023-06-12 18:40:16 +02:00
//-----------------------------------------------------------------------------
// Purpose: get address of imported function in target module
// Input : *szModuleName -
// *szFunctionName -
// bGetFunctionReference -
// Output : CMemory
//-----------------------------------------------------------------------------
CMemory CModule : : GetImportedFunction ( const char * szModuleName , const char * szFunctionName , const bool bGetFunctionReference ) const
2023-01-31 23:52:11 +01:00
{
if ( ! m_pDOSHeader | | m_pDOSHeader - > e_magic ! = IMAGE_DOS_SIGNATURE ) // Is dosHeader valid?
return CMemory ( ) ;
if ( ! m_pNTHeaders | | m_pNTHeaders - > Signature ! = IMAGE_NT_SIGNATURE ) // Is ntHeader valid?
return CMemory ( ) ;
// Get the location of IMAGE_IMPORT_DESCRIPTOR for this module by adding the IMAGE_DIRECTORY_ENTRY_IMPORT relative virtual address onto our module base address.
IMAGE_IMPORT_DESCRIPTOR * pImageImportDescriptors = reinterpret_cast < IMAGE_IMPORT_DESCRIPTOR * > ( m_pModuleBase + m_pNTHeaders - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_IMPORT ] . VirtualAddress ) ;
if ( ! pImageImportDescriptors )
return CMemory ( ) ;
for ( IMAGE_IMPORT_DESCRIPTOR * pIID = pImageImportDescriptors ; pIID - > Name ! = 0 ; pIID + + )
{
// Get virtual relative Address of the imported module name. Then add module base Address to get the actual location.
2023-06-12 18:40:16 +02:00
const char * szImportedModuleName = reinterpret_cast < char * > ( reinterpret_cast < DWORD * > ( m_pModuleBase + pIID - > Name ) ) ;
2023-01-31 23:52:11 +01:00
2023-06-12 18:40:16 +02:00
if ( stricmp ( szImportedModuleName , szModuleName ) = = 0 ) // Is this our wanted imported module?.
2023-01-31 23:52:11 +01:00
{
// Original First Thunk to get function name.
IMAGE_THUNK_DATA * pOgFirstThunk = reinterpret_cast < IMAGE_THUNK_DATA * > ( m_pModuleBase + pIID - > OriginalFirstThunk ) ;
// To get actual function address.
IMAGE_THUNK_DATA * pFirstThunk = reinterpret_cast < IMAGE_THUNK_DATA * > ( m_pModuleBase + pIID - > FirstThunk ) ;
for ( ; pOgFirstThunk - > u1 . AddressOfData ; + + pOgFirstThunk , + + pFirstThunk )
{
// Get image import by name.
const IMAGE_IMPORT_BY_NAME * pImageImportByName = reinterpret_cast < IMAGE_IMPORT_BY_NAME * > ( m_pModuleBase + pOgFirstThunk - > u1 . AddressOfData ) ;
2023-06-12 18:40:16 +02:00
if ( strcmp ( pImageImportByName - > Name , szFunctionName ) = = 0 ) // Is this our wanted imported function?
2023-01-31 23:52:11 +01:00
{
// Grab function address from firstThunk.
uintptr_t * pFunctionAddress = & pFirstThunk - > u1 . Function ;
// Reference or address?
return bGetFunctionReference ? CMemory ( pFunctionAddress ) : CMemory ( * pFunctionAddress ) ; // Return as CMemory class.
}
}
}
}
return CMemory ( ) ;
}
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
// Purpose: get address of exported function in this module
2023-06-12 18:40:16 +02:00
// Input : *szFunctionName -
2022-04-10 19:59:34 +02:00
// bNullTerminator -
// Output : CMemory
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CMemory CModule : : GetExportedFunction ( const char * szFunctionName ) const
2022-04-10 19:59:34 +02:00
{
if ( ! m_pDOSHeader | | m_pDOSHeader - > e_magic ! = IMAGE_DOS_SIGNATURE ) // Is dosHeader valid?
return CMemory ( ) ;
if ( ! m_pNTHeaders | | m_pNTHeaders - > Signature ! = IMAGE_NT_SIGNATURE ) // Is ntHeader valid?
return CMemory ( ) ;
2022-07-20 11:27:42 +02:00
// Get the location of IMAGE_EXPORT_DIRECTORY for this module by adding the IMAGE_DIRECTORY_ENTRY_EXPORT relative virtual address onto our module base address.
2022-07-15 19:43:29 +02:00
const IMAGE_EXPORT_DIRECTORY * pImageExportDirectory = reinterpret_cast < IMAGE_EXPORT_DIRECTORY * > ( m_pModuleBase + m_pNTHeaders - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] . VirtualAddress ) ;
2022-04-10 19:59:34 +02:00
if ( ! pImageExportDirectory )
return CMemory ( ) ;
// Are there any exported functions?
if ( ! pImageExportDirectory - > NumberOfFunctions )
return CMemory ( ) ;
2022-07-20 11:27:42 +02:00
// Get the location of the functions via adding the relative virtual address from the struct into our module base address.
2022-07-15 19:43:29 +02:00
const DWORD * pAddressOfFunctions = reinterpret_cast < DWORD * > ( m_pModuleBase + pImageExportDirectory - > AddressOfFunctions ) ;
2022-04-10 19:59:34 +02:00
if ( ! pAddressOfFunctions )
return CMemory ( ) ;
2022-07-20 11:27:42 +02:00
// Get the names of the functions via adding the relative virtual address from the struct into our module base Address.
2022-07-15 19:43:29 +02:00
const DWORD * pAddressOfName = reinterpret_cast < DWORD * > ( m_pModuleBase + pImageExportDirectory - > AddressOfNames ) ;
2022-04-10 19:59:34 +02:00
if ( ! pAddressOfName )
return CMemory ( ) ;
2022-07-20 11:27:42 +02:00
// Get the ordinals of the functions via adding the relative virtual Address from the struct into our module base address.
2022-04-10 19:59:34 +02:00
DWORD * pAddressOfOrdinals = reinterpret_cast < DWORD * > ( m_pModuleBase + pImageExportDirectory - > AddressOfNameOrdinals ) ;
if ( ! pAddressOfOrdinals )
return CMemory ( ) ;
for ( DWORD i = 0 ; i < pImageExportDirectory - > NumberOfFunctions ; i + + ) // Iterate through all the functions.
{
// Get virtual relative Address of the function name. Then add module base Address to get the actual location.
2023-06-12 18:40:16 +02:00
const char * ExportFunctionName = reinterpret_cast < char * > ( reinterpret_cast < DWORD * > ( m_pModuleBase + pAddressOfName [ i ] ) ) ;
2022-04-10 19:59:34 +02:00
2023-06-12 18:40:16 +02:00
if ( strcmp ( ExportFunctionName , szFunctionName ) = = 0 ) // Is this our wanted exported function?
2022-04-10 19:59:34 +02:00
{
2022-07-20 11:27:42 +02:00
// Get the function ordinal. Then grab the relative virtual address of our wanted function. Then add module base address so we get the actual location.
return CMemory ( m_pModuleBase + pAddressOfFunctions [ reinterpret_cast < WORD * > ( pAddressOfOrdinals ) [ i ] ] ) ; // Return as CMemory class.
2022-04-10 19:59:34 +02:00
}
}
return CMemory ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: get the module section by name (example: '.rdata', '.text')
2023-06-12 18:40:16 +02:00
// Input : *szSectionName -
2022-04-10 19:59:34 +02:00
// Output : ModuleSections_t
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
CModule : : ModuleSections_t CModule : : GetSectionByName ( const char * szSectionName ) const
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
for ( const ModuleSections_t & section : m_ModuleSections )
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
if ( section . m_SectionName . compare ( szSectionName ) = = 0 )
2022-12-04 00:01:31 +01:00
return section ;
2022-04-10 19:59:34 +02:00
}
return ModuleSections_t ( ) ;
}
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
// Purpose: unlink module from peb
2022-04-10 19:59:34 +02:00
//-----------------------------------------------------------------------------
2023-06-12 18:40:16 +02:00
void CModule : : UnlinkFromPEB ( ) const // Disclaimer: This does not bypass GetMappedFileName. That function calls NtQueryVirtualMemory which does a syscall to ntoskrnl for getting info on a section.
2022-04-10 19:59:34 +02:00
{
2023-06-12 18:40:16 +02:00
# define UNLINK_FROM_PEB(entry) \
( entry ) . Flink - > Blink = ( entry ) . Blink ; \
( entry ) . Blink - > Flink = ( entry ) . Flink ;
2022-04-10 19:59:34 +02:00
2023-06-12 18:40:16 +02:00
const PEB64 * processEnvBlock = reinterpret_cast < PEB64 * > ( __readgsqword ( 0x60 ) ) ; // https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
const LIST_ENTRY * inLoadOrderList = & processEnvBlock - > Ldr - > InLoadOrderModuleList ;
2022-05-03 02:37:37 +02:00
2023-06-12 18:40:16 +02:00
for ( LIST_ENTRY * entry = inLoadOrderList - > Flink ; entry ! = inLoadOrderList ; entry = entry - > Flink )
{
const PLDR_DATA_TABLE_ENTRY pldrEntry = reinterpret_cast < PLDR_DATA_TABLE_ENTRY > ( entry - > Flink ) ;
const std : : uintptr_t baseAddr = reinterpret_cast < std : : uintptr_t > ( pldrEntry - > DllBase ) ;
2022-12-02 00:30:49 +01:00
2023-06-12 18:40:16 +02:00
if ( baseAddr ! = m_pModuleBase )
continue ;
UNLINK_FROM_PEB ( pldrEntry - > InInitializationOrderLinks ) ;
UNLINK_FROM_PEB ( pldrEntry - > InMemoryOrderLinks ) ;
UNLINK_FROM_PEB ( pldrEntry - > InLoadOrderLinks ) ;
break ;
}
# undef UNLINK_FROM_PEB
2022-12-02 00:30:49 +01:00
}