2021-07-20 23:28:54 +02:00
# pragma once
2021-12-25 22:36:38 +01:00
# include "public/include/utility.h"
2021-07-20 23:28:54 +02:00
2021-12-25 22:36:38 +01:00
class ADDRESS
2021-07-20 23:28:54 +02:00
{
public :
enum class Direction : int
{
2021-08-09 18:12:27 +02:00
DOWN = 0 ,
UP ,
2021-07-20 23:28:54 +02:00
} ;
std : : uintptr_t GetPtr ( )
{
return ptr ;
}
2021-12-25 22:36:38 +01:00
ADDRESS ( ) = default ;
ADDRESS ( std : : uintptr_t ptr ) : ptr ( ptr ) { }
ADDRESS ( void * ptr ) : ptr ( std : : uintptr_t ( ptr ) ) { }
2021-07-20 23:28:54 +02:00
operator std : : uintptr_t ( ) const
{
return ptr ;
}
operator void * ( )
{
return reinterpret_cast < void * > ( ptr ) ;
}
operator bool ( )
{
return ptr ! = NULL ;
}
2021-12-25 22:36:38 +01:00
bool operator ! = ( const ADDRESS & addr ) const
2021-07-20 23:28:54 +02:00
{
return ptr ! = addr . ptr ;
}
2021-12-25 22:36:38 +01:00
bool operator = = ( const ADDRESS & addr ) const
2021-07-20 23:28:54 +02:00
{
return ptr = = addr . ptr ;
}
bool operator = = ( const std : : uintptr_t & addr ) const
{
return ptr = = addr ;
}
template < typename T > T CCast ( )
{
return ( T ) ptr ;
}
template < typename T > T RCast ( )
{
return reinterpret_cast < T > ( ptr ) ;
}
2021-07-21 16:15:32 +02:00
template < class T > T GetValue ( )
{
return * reinterpret_cast < T * > ( ptr ) ;
}
2021-12-25 22:36:38 +01:00
ADDRESS Offset ( std : : ptrdiff_t offset )
2021-07-20 23:28:54 +02:00
{
2021-12-25 22:36:38 +01:00
return ADDRESS ( ptr + offset ) ;
2021-07-20 23:28:54 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS OffsetSelf ( std : : ptrdiff_t offset )
2021-07-20 23:28:54 +02:00
{
ptr + = offset ;
return * this ;
}
2021-12-25 22:36:38 +01:00
ADDRESS Deref ( int deref = 1 )
2021-07-20 23:28:54 +02:00
{
2021-07-21 19:34:19 +02:00
std : : uintptr_t reference = ptr ;
2021-07-20 23:28:54 +02:00
while ( deref - - )
{
if ( reference )
reference = * reinterpret_cast < std : : uintptr_t * > ( reference ) ;
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( reference ) ;
2021-07-20 23:28:54 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS DerefSelf ( int deref = 1 )
2021-07-20 23:28:54 +02:00
{
while ( deref - - )
{
if ( ptr )
ptr = * reinterpret_cast < std : : uintptr_t * > ( ptr ) ;
}
return * this ;
}
2021-07-21 16:15:32 +02:00
bool CheckOpCodes ( const std : : vector < std : : uint8_t > opcodeArray )
2021-07-20 23:28:54 +02:00
{
2021-07-21 16:15:32 +02:00
std : : uintptr_t reference = ptr ; // Create pointer reference.
for ( auto [ byteAtCurrentAddress , i ] = std : : tuple { std : : uint8_t ( ) , ( std : : size_t ) 0 } ; i < opcodeArray . size ( ) ; i + + , reference + + ) // Loop forward in the ptr class member.
{
2021-12-25 22:36:38 +01:00
byteAtCurrentAddress = * reinterpret_cast < std : : uint8_t * > ( reference ) ; // Get byte at current Address.
2021-07-21 16:15:32 +02:00
if ( byteAtCurrentAddress ! = opcodeArray [ i ] ) // If byte at ptr doesn't equal in the byte array return false.
return false ;
}
return true ;
2021-07-20 23:28:54 +02:00
}
template < class T > T GetVirtualFunctionIndex ( )
{
2021-07-21 16:15:32 +02:00
return * reinterpret_cast < T * > ( ptr ) / 8 ; // Its divided by 8 in x64.
2021-07-20 23:28:54 +02:00
}
2021-07-21 16:15:32 +02:00
void Patch ( std : : vector < std : : uint8_t > opcodes )
2021-07-20 23:28:54 +02:00
{
DWORD oldProt = NULL ;
SIZE_T dwSize = opcodes . size ( ) ;
2021-07-21 16:15:32 +02:00
VirtualProtect ( ( void * ) ptr , dwSize , PAGE_EXECUTE_READWRITE , & oldProt ) ; // Patch page to be able to read and write to it.
2021-07-20 23:28:54 +02:00
for ( int i = 0 ; i < opcodes . size ( ) ; i + + )
{
2021-12-25 22:36:38 +01:00
* ( std : : uint8_t * ) ( ptr + i ) = opcodes [ i ] ; // Write opcodes to Address.
2021-07-20 23:28:54 +02:00
}
dwSize = opcodes . size ( ) ;
2021-07-21 16:15:32 +02:00
VirtualProtect ( ( void * ) ptr , dwSize , oldProt , & oldProt ) ; // Restore protection.
}
2021-12-25 22:36:38 +01:00
ADDRESS FindPatternSelf ( const std : : string pattern , const Direction searchDirect , const int opCodesToScan = 100 , const std : : ptrdiff_t occurence = 1 )
2021-07-21 16:15:32 +02:00
{
2021-08-09 18:12:27 +02:00
static auto PatternToBytes = [ ] ( const std : : string pattern )
2021-07-21 16:15:32 +02:00
{
2021-08-09 18:12:27 +02:00
char * PatternStart = const_cast < char * > ( pattern . c_str ( ) ) ; // Cast const away and get start of pattern.
char * PatternEnd = PatternStart + std : : strlen ( pattern . c_str ( ) ) ; // Get end of pattern.
2021-07-21 16:15:32 +02:00
std : : vector < std : : int32_t > Bytes = std : : vector < std : : int32_t > { } ; // Initialize byte vector.
for ( char * CurrentByte = PatternStart ; CurrentByte < PatternEnd ; + + CurrentByte )
{
if ( * CurrentByte = = ' ? ' ) // Is current char(byte) a wildcard?
{
+ + CurrentByte ; // Skip 1 character.
if ( * CurrentByte = = ' ? ' ) // Is it a double wildcard pattern?
+ + CurrentByte ; // If so skip the next space that will come up so we can reach the next byte.
Bytes . push_back ( - 1 ) ; // Push the byte back as invalid.
}
else
{
// https://stackoverflow.com/a/43860875/12541255
// Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal.
// Afterwards we push the byte into our bytes vector.
Bytes . push_back ( std : : strtoul ( CurrentByte , & CurrentByte , 16 ) ) ;
}
}
return Bytes ;
} ;
std : : uint8_t * ScanBytes = reinterpret_cast < std : : uint8_t * > ( ptr ) ; // Get the base of the module.
const std : : vector < int > PatternBytes = PatternToBytes ( pattern ) ; // Convert our pattern to a byte array.
const std : : pair BytesInfo = std : : make_pair ( PatternBytes . size ( ) , PatternBytes . data ( ) ) ; // Get the size and data of our bytes.
2021-08-09 18:12:27 +02:00
std : : ptrdiff_t occurences = 0 ;
2021-07-21 16:15:32 +02:00
2021-08-09 18:12:27 +02:00
for ( long i = 01 ; i < opCodesToScan + BytesInfo . first ; i + + )
2021-07-21 16:15:32 +02:00
{
bool FoundAddress = true ;
2021-08-09 18:12:27 +02:00
int memOffset = searchDirect = = Direction : : DOWN ? i : - i ;
for ( DWORD j = 0ul ; j < BytesInfo . first ; j + + )
2021-07-21 16:15:32 +02:00
{
// 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.
2021-08-09 18:12:27 +02:00
std : : uint8_t currentByte = * ( ScanBytes + memOffset + j ) ;
if ( currentByte ! = BytesInfo . second [ j ] & & BytesInfo . second [ j ] ! = - 1 )
2021-07-21 16:15:32 +02:00
{
FoundAddress = false ;
break ;
}
}
if ( FoundAddress )
{
occurences + + ;
if ( occurence = = occurences )
{
2021-08-09 18:12:27 +02:00
ptr = std : : uintptr_t ( & * ( ScanBytes + memOffset ) ) ;
2021-07-21 16:15:32 +02:00
return * this ;
}
}
}
ptr = std : : uintptr_t ( ) ;
return * this ;
2021-07-20 23:28:54 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS FindPattern ( const std : : string pattern , const Direction searchDirect , const int opCodesToScan = 100 , const std : : ptrdiff_t occurence = 1 )
2021-07-20 23:28:54 +02:00
{
2021-08-09 18:12:27 +02:00
static auto PatternToBytes = [ ] ( const std : : string pattern )
2021-07-20 23:28:54 +02:00
{
2021-08-09 18:12:27 +02:00
char * PatternStart = const_cast < char * > ( pattern . c_str ( ) ) ; // Cast const away and get start of pattern.
char * PatternEnd = PatternStart + std : : strlen ( pattern . c_str ( ) ) ; // Get end of pattern.
2021-07-20 23:28:54 +02:00
std : : vector < std : : int32_t > Bytes = std : : vector < std : : int32_t > { } ; // Initialize byte vector.
for ( char * CurrentByte = PatternStart ; CurrentByte < PatternEnd ; + + CurrentByte )
{
if ( * CurrentByte = = ' ? ' ) // Is current char(byte) a wildcard?
{
+ + CurrentByte ; // Skip 1 character.
if ( * CurrentByte = = ' ? ' ) // Is it a double wildcard pattern?
+ + CurrentByte ; // If so skip the next space that will come up so we can reach the next byte.
Bytes . push_back ( - 1 ) ; // Push the byte back as invalid.
}
else
{
// https://stackoverflow.com/a/43860875/12541255
// Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal.
// Afterwards we push the byte into our bytes vector.
Bytes . push_back ( std : : strtoul ( CurrentByte , & CurrentByte , 16 ) ) ;
}
}
return Bytes ;
} ;
std : : uint8_t * ScanBytes = reinterpret_cast < std : : uint8_t * > ( ptr ) ; // Get the base of the module.
const std : : vector < int > PatternBytes = PatternToBytes ( pattern ) ; // Convert our pattern to a byte array.
const std : : pair BytesInfo = std : : make_pair ( PatternBytes . size ( ) , PatternBytes . data ( ) ) ; // Get the size and data of our bytes.
2021-08-09 18:12:27 +02:00
std : : ptrdiff_t occurences = 0 ;
2021-07-20 23:28:54 +02:00
2021-08-09 18:12:27 +02:00
for ( long i = 01 ; i < opCodesToScan + BytesInfo . first ; i + + )
2021-07-20 23:28:54 +02:00
{
bool FoundAddress = true ;
2021-08-09 18:12:27 +02:00
int memOffset = searchDirect = = Direction : : DOWN ? i : - i ;
2021-07-20 23:28:54 +02:00
2021-08-09 18:12:27 +02:00
for ( DWORD j = 0ul ; j < BytesInfo . first ; j + + )
2021-07-20 23:28:54 +02:00
{
// 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.
2021-08-09 18:12:27 +02:00
std : : uint8_t currentByte = * ( ScanBytes + memOffset + j ) ;
if ( currentByte ! = BytesInfo . second [ j ] & & BytesInfo . second [ j ] ! = - 1 )
2021-07-20 23:28:54 +02:00
{
FoundAddress = false ;
break ;
}
}
if ( FoundAddress )
{
2021-07-21 16:15:32 +02:00
occurences + + ;
if ( occurence = = occurences )
{
2021-12-25 22:36:38 +01:00
return ADDRESS ( & * ( ScanBytes + memOffset ) ) ;
2021-07-21 16:15:32 +02:00
}
2021-07-20 23:28:54 +02:00
}
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-07-20 23:28:54 +02:00
}
2021-07-21 16:15:32 +02:00
2021-12-25 22:36:38 +01:00
ADDRESS FollowNearCall ( std : : ptrdiff_t opcodeOffset = 0x1 , std : : ptrdiff_t nextInstructionOffset = 0x5 )
2021-07-21 16:15:32 +02:00
{
2021-08-19 15:26:44 +02:00
return ResolveRelativeAddress ( opcodeOffset , nextInstructionOffset ) ;
}
2021-12-25 22:36:38 +01:00
ADDRESS FollowNearCallSelf ( std : : ptrdiff_t opcodeOffset = 0x1 , std : : ptrdiff_t nextInstructionOffset = 0x5 )
2021-08-19 15:26:44 +02:00
{
return ResolveRelativeAddressSelf ( opcodeOffset , nextInstructionOffset ) ;
}
2021-12-25 22:36:38 +01:00
ADDRESS ResolveRelativeAddressSelf ( std : : ptrdiff_t registerOffset = 0x0 , std : : ptrdiff_t nextInstructionOffset = 0x4 )
2021-08-19 15:26:44 +02:00
{
// Skip register.
std : : uintptr_t skipRegister = ptr + registerOffset ;
2021-07-21 16:15:32 +02:00
2021-12-25 22:36:38 +01:00
// Get 4-byte long relative Address.
2021-08-19 15:26:44 +02:00
std : : int32_t relativeAddress = * reinterpret_cast < std : : int32_t * > ( skipRegister ) ;
2021-07-21 16:15:32 +02:00
// Get location of next instruction.
std : : uintptr_t nextInstruction = ptr + nextInstructionOffset ;
2021-12-25 22:36:38 +01:00
// Get function location via adding relative Address to next instruction.
2021-08-19 15:26:44 +02:00
ptr = nextInstruction + relativeAddress ;
return * this ;
2021-07-21 16:15:32 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS ResolveRelativeAddress ( std : : ptrdiff_t registerOffset = 0x0 , std : : ptrdiff_t nextInstructionOffset = 0x4 )
2021-07-21 16:15:32 +02:00
{
2021-08-19 15:26:44 +02:00
// Skip register.
std : : uintptr_t skipRegister = ptr + registerOffset ;
2021-07-21 16:15:32 +02:00
2021-12-25 22:36:38 +01:00
// Get 4-byte long relative Address.
2021-08-19 15:26:44 +02:00
std : : int32_t relativeAddress = * reinterpret_cast < std : : int32_t * > ( skipRegister ) ;
2021-07-21 16:15:32 +02:00
// Get location of next instruction.
std : : uintptr_t nextInstruction = ptr + nextInstructionOffset ;
2021-12-25 22:36:38 +01:00
// Get function location via adding relative Address to next instruction.
return ADDRESS ( nextInstruction + relativeAddress ) ;
2021-07-21 16:15:32 +02:00
}
2021-08-19 15:26:44 +02:00
2021-07-20 23:28:54 +02:00
private :
std : : uintptr_t ptr = 0 ;
} ;
2021-12-25 22:36:38 +01:00
class MODULE
2021-07-20 23:28:54 +02:00
{
public :
2021-08-09 18:12:27 +02:00
struct ModuleSections
{
ModuleSections ( ) = default ;
ModuleSections ( std : : string sectionName , std : : uintptr_t sectionStartAddress , DWORD sectionSize ) : sectionName ( sectionName ) , sectionStartAddress ( sectionStartAddress ) , sectionSize ( sectionSize ) { }
bool IsSectionValid ( )
{
return sectionSize ! = 0 ;
}
std : : string sectionName = std : : string ( ) ; // Name of section.
2021-12-25 22:36:38 +01:00
std : : uintptr_t sectionStartAddress = 0 ; // Start memory Address of section.
2021-08-09 18:12:27 +02:00
DWORD sectionSize = 0 ; // Size of section.
} ;
ModuleSections GetSectionByName ( const std : : string sectionName )
{
for ( ModuleSections & currentSection : moduleSections )
{
if ( currentSection . sectionName . compare ( sectionName ) = = 0 )
return currentSection ;
}
return ModuleSections ( ) ;
}
2021-12-25 22:36:38 +01:00
MODULE ( ) = default ;
MODULE ( std : : string moduleName ) : moduleName ( moduleName )
2021-07-20 23:28:54 +02:00
{
const MODULEINFO mInfo = GetModuleInfo ( moduleName . c_str ( ) ) ; // Get module info.
sizeOfModule = ( DWORD64 ) mInfo . SizeOfImage ; // Grab the module size.
moduleBase = ( std : : uintptr_t ) mInfo . lpBaseOfDll ; // Grab module base.
2021-08-09 18:12:27 +02:00
dosHeader = reinterpret_cast < IMAGE_DOS_HEADER * > ( moduleBase ) ; // Get dosHeader.
ntHeaders = reinterpret_cast < IMAGE_NT_HEADERS64 * > ( moduleBase + dosHeader - > e_lfanew ) ; // Get ntHeaders.
const IMAGE_SECTION_HEADER * hSection = IMAGE_FIRST_SECTION ( ntHeaders ) ; // Get first image section.
for ( WORD i = 0 ; i < ntHeaders - > FileHeader . NumberOfSections ; i + + ) // Loop through the sections.
{
const IMAGE_SECTION_HEADER & currentSection = hSection [ i ] ; // Get current section.
moduleSections . push_back ( ModuleSections ( std : : string ( reinterpret_cast < const char * > ( currentSection . Name ) ) , ( std : : uintptr_t ) ( DWORD64 ) ( moduleBase + currentSection . VirtualAddress ) , currentSection . SizeOfRawData ) ) ; // Push back a struct with the section data.
}
2021-07-20 23:28:54 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS PatternSearch ( const std : : string pattern , const std : : ptrdiff_t patternOccurence = 1 )
2021-07-20 23:28:54 +02:00
{
2021-08-09 18:12:27 +02:00
static auto PatternToBytes = [ ] ( const std : : string pattern )
2021-07-20 23:28:54 +02:00
{
2021-08-09 18:12:27 +02:00
char * PatternStart = const_cast < char * > ( pattern . c_str ( ) ) ; // Cast const away and get start of pattern.
char * PatternEnd = PatternStart + std : : strlen ( pattern . c_str ( ) ) ; // Get end of pattern.
2021-07-20 23:28:54 +02:00
std : : vector < std : : int32_t > Bytes = std : : vector < std : : int32_t > { } ; // Initialize byte vector.
for ( char * CurrentByte = PatternStart ; CurrentByte < PatternEnd ; + + CurrentByte )
{
if ( * CurrentByte = = ' ? ' ) // Is current char(byte) a wildcard?
{
+ + CurrentByte ; // Skip 1 character.
if ( * CurrentByte = = ' ? ' ) // Is it a double wildcard pattern?
+ + CurrentByte ; // If so skip the next space that will come up so we can reach the next byte.
Bytes . push_back ( - 1 ) ; // Push the byte back as invalid.
}
else
{
// https://stackoverflow.com/a/43860875/12541255
// Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal.
// Afterwards we push the byte into our bytes vector.
Bytes . push_back ( std : : strtoul ( CurrentByte , & CurrentByte , 16 ) ) ;
}
}
return Bytes ;
} ;
2021-08-09 18:12:27 +02:00
ModuleSections textSection = GetSectionByName ( " .text " ) ; // Get the .text section.
if ( ! textSection . IsSectionValid ( ) )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-07-20 23:28:54 +02:00
2021-08-09 18:12:27 +02:00
const std : : vector < std : : int32_t > PatternBytes = PatternToBytes ( pattern ) ; // Convert our pattern to a byte array.
2021-07-20 23:28:54 +02:00
const std : : pair BytesInfo = std : : make_pair ( PatternBytes . size ( ) , PatternBytes . data ( ) ) ; // Get the size and data of our bytes.
2021-08-09 18:12:27 +02:00
std : : uint8_t * latestOccurence = nullptr ;
std : : ptrdiff_t occurencesFound = 0 ;
std : : uint8_t * StartOfCodeSection = reinterpret_cast < std : : uint8_t * > ( textSection . sectionStartAddress ) ; // Get start of .text section.
for ( DWORD i = 0ul ; i < textSection . sectionSize - BytesInfo . first ; i + + )
2021-07-20 23:28:54 +02:00
{
bool FoundAddress = true ;
2021-08-09 18:12:27 +02:00
for ( DWORD j = 0ul ; j < BytesInfo . first ; j + + )
2021-07-20 23:28:54 +02:00
{
// 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.
2021-08-09 18:12:27 +02:00
if ( StartOfCodeSection [ i + j ] ! = BytesInfo . second [ j ] & & BytesInfo . second [ j ] ! = - 1 )
2021-07-20 23:28:54 +02:00
{
FoundAddress = false ;
break ;
}
}
if ( FoundAddress )
{
2021-08-09 18:12:27 +02:00
occurencesFound + + ; // Increment occurences found counter.
if ( patternOccurence = = occurencesFound ) // Is it the occurence we want?
2021-12-25 22:36:38 +01:00
return ADDRESS ( & StartOfCodeSection [ i ] ) ; // If yes return it.
2021-08-09 18:12:27 +02:00
latestOccurence = & StartOfCodeSection [ i ] ; // Stash latest occurence.
}
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( latestOccurence ) ;
2021-08-09 18:12:27 +02:00
}
2021-08-14 01:56:05 +02:00
2021-12-25 22:36:38 +01:00
ADDRESS FindPatternSIMD ( std : : uint8_t * szPattern , const char * szMask )
{
ModuleSections mInfo = GetSectionByName ( " .text " ) ; // Get the .text section.
if ( ! mInfo . IsSectionValid ( ) ) { return ADDRESS ( ) ; }
DWORD64 base = ( DWORD64 ) mInfo . sectionStartAddress ;
DWORD64 size = ( DWORD64 ) mInfo . sectionSize ;
unsigned char * pData = ( unsigned char * ) base ;
unsigned int length = ( unsigned int ) size ;
const unsigned char * end = pData + length - strlen ( szMask ) ;
int num_masks = ( int ) ceil ( ( float ) strlen ( szMask ) / ( float ) 16 ) ;
int masks [ 32 ] ; // 32*16 = enough masks for 512 bytes.
memset ( masks , 0 , num_masks * sizeof ( int ) ) ;
for ( int64_t i = 0 ; i < num_masks ; + + i )
{
for ( int64_t j = strnlen ( szMask + i * 16 , 16 ) - 1 ; j > = 0 ; - - j )
{
if ( szMask [ i * 16 + j ] = = ' x ' )
{
masks [ i ] | = 1 < < j ;
}
}
}
__m128i xmm1 = _mm_loadu_si128 ( ( const __m128i * ) szPattern ) ;
__m128i xmm2 , xmm3 , msks ;
for ( ; pData ! = end ; _mm_prefetch ( ( const char * ) ( + + pData + 64 ) , _MM_HINT_NTA ) )
{
if ( szPattern [ 0 ] = = pData [ 0 ] )
{
xmm2 = _mm_loadu_si128 ( ( const __m128i * ) pData ) ;
msks = _mm_cmpeq_epi8 ( xmm1 , xmm2 ) ;
if ( ( _mm_movemask_epi8 ( msks ) & masks [ 0 ] ) = = masks [ 0 ] )
{
for ( DWORD64 i = 1 ; i < num_masks ; + + i )
{
xmm2 = _mm_loadu_si128 ( ( const __m128i * ) ( pData + i * 16 ) ) ;
xmm3 = _mm_loadu_si128 ( ( const __m128i * ) ( szPattern + i * 16 ) ) ;
msks = _mm_cmpeq_epi8 ( xmm2 , xmm3 ) ;
if ( ( _mm_movemask_epi8 ( msks ) & masks [ i ] ) = = masks [ i ] )
{
if ( ( i + 1 ) = = num_masks )
{
return ( ADDRESS ) pData ;
}
}
else goto cont ;
}
return ( ADDRESS ) ( & * ( pData ) ) ;
}
} cont : ;
}
return ADDRESS ( ) ;
}
ADDRESS GetExportedFunction ( const std : : string functionName )
2021-08-14 01:56:05 +02:00
{
if ( ! dosHeader | | dosHeader - > e_magic ! = IMAGE_DOS_SIGNATURE ) // Is dosHeader valid?
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
if ( ! ntHeaders | | ntHeaders - > Signature ! = IMAGE_NT_SIGNATURE ) // Is ntHeader valid?
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
2021-12-25 22:36:38 +01: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.
2021-08-14 01:56:05 +02:00
IMAGE_EXPORT_DIRECTORY * ImageExportDirectory = reinterpret_cast < IMAGE_EXPORT_DIRECTORY * > ( moduleBase + ntHeaders - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] . VirtualAddress ) ;
if ( ! ImageExportDirectory )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
// Are there any exported functions?
if ( ! ImageExportDirectory - > NumberOfFunctions )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
2021-12-25 22:36:38 +01:00
// Get the location of the functions via adding the relative virtual Address from the struct into our module base Address.
2021-08-14 01:56:05 +02:00
DWORD * AddressOfFunctionsPtr = reinterpret_cast < DWORD * > ( moduleBase + ImageExportDirectory - > AddressOfFunctions ) ;
if ( ! AddressOfFunctionsPtr )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
2021-12-25 22:36:38 +01:00
// Get the names of the functions via adding the relative virtual Address from the struct into our module base Address.
2021-08-14 01:56:05 +02:00
DWORD * AddressOfNamePtr = reinterpret_cast < DWORD * > ( moduleBase + ImageExportDirectory - > AddressOfNames ) ;
if ( ! AddressOfNamePtr )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
2021-12-25 22:36:38 +01:00
// Get the ordinals of the functions via adding the relative virtual Address from the struct into our module base Address.
2021-08-14 01:56:05 +02:00
DWORD * AddressOfOrdinalsPtr = reinterpret_cast < DWORD * > ( moduleBase + ImageExportDirectory - > AddressOfNameOrdinals ) ;
if ( ! AddressOfOrdinalsPtr )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
for ( std : : size_t i = 0 ; i < ImageExportDirectory - > NumberOfFunctions ; i + + ) // Iterate through all the functions.
{
2021-12-25 22:36:38 +01:00
// Get virtual relative Address of the function name. Then add module base Address to get the actual location.
2021-08-14 01:56:05 +02:00
std : : string ExportFunctionName = reinterpret_cast < char * > ( reinterpret_cast < DWORD * > ( moduleBase + AddressOfNamePtr [ i ] ) ) ;
if ( ExportFunctionName . compare ( functionName ) = = 0 ) // Is this our wanted exported function?
{
2021-12-25 22:36:38 +01: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 ADDRESS ( moduleBase + AddressOfFunctionsPtr [ reinterpret_cast < WORD * > ( AddressOfOrdinalsPtr ) [ i ] ] ) ; // Return as Address class.
2021-08-14 01:56:05 +02:00
}
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-14 01:56:05 +02:00
}
2021-08-09 18:12:27 +02:00
2021-12-25 22:36:38 +01:00
ADDRESS FindAddressForString ( const std : : string string , bool nullTerminator )
2021-08-09 18:12:27 +02:00
{
static auto StringToBytes = [ ] ( const std : : string string , bool nullTerminator )
{
char * StringStart = const_cast < char * > ( string . c_str ( ) ) ; // Cast const away and get start of string.
char * StringEnd = StringStart + std : : strlen ( string . c_str ( ) ) ; // Get end of string.
std : : vector < std : : int32_t > Bytes = std : : vector < std : : int32_t > { } ; // Initialize byte vector.
for ( char * CurrentByte = StringStart ; CurrentByte < StringEnd ; + + CurrentByte ) // Loop through all the characters in the .rdata string.
{
Bytes . push_back ( * CurrentByte ) ; // Dereference character and push back the byte.
}
if ( nullTerminator ) // Does the string have a null terminator at the end of it?
Bytes . push_back ( 0x0 ) ; // If yes push back 0 at the end of the byte array.
return Bytes ;
} ;
ModuleSections rdataSection = GetSectionByName ( " .rdata " ) ; // .Get rdata section, we only loop through here because most important strings are in the .rdata section.
if ( ! rdataSection . IsSectionValid ( ) )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-09 18:12:27 +02:00
std : : vector < std : : int32_t > stringBytes = StringToBytes ( string , nullTerminator ) ; // Convert our string to a byte array.
const std : : pair BytesInfo = std : : make_pair ( stringBytes . size ( ) , stringBytes . data ( ) ) ; // Get the size and data of our bytes.
std : : uint8_t * StartOfRdata = reinterpret_cast < std : : uint8_t * > ( rdataSection . sectionStartAddress ) ; // Get start of .rdata section.
for ( DWORD i = 0ul ; i < rdataSection . sectionSize - BytesInfo . first ; i + + )
{
bool FoundAddress = 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 ( DWORD j = 0ul ; j < BytesInfo . first ; j + + )
{
if ( StartOfRdata [ i + j ] ! = BytesInfo . second [ j ] & & BytesInfo . second [ j ] ! = - 1 )
{
FoundAddress = false ;
break ;
}
}
if ( FoundAddress )
{
2021-12-25 22:36:38 +01:00
return ADDRESS ( & StartOfRdata [ i ] ) ;
2021-07-20 23:28:54 +02:00
}
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-07-20 23:28:54 +02:00
}
2021-12-25 22:36:38 +01:00
ADDRESS StringSearch ( const std : : string string , const std : : ptrdiff_t occurence = 1 , bool nullTerminator = false )
2021-08-09 18:12:27 +02:00
{
static auto PatternToBytes = [ ] ( const std : : string pattern )
{
char * PatternStart = const_cast < char * > ( pattern . c_str ( ) ) ; // Cast const away and get start of pattern.
char * PatternEnd = PatternStart + std : : strlen ( pattern . c_str ( ) ) ; // Get end of pattern.
std : : vector < std : : int32_t > Bytes = std : : vector < std : : int32_t > { } ; // Initialize byte vector.
for ( char * CurrentByte = PatternStart ; CurrentByte < PatternEnd ; + + CurrentByte )
{
if ( * CurrentByte = = ' ? ' ) // Is current char(byte) a wildcard?
{
+ + CurrentByte ; // Skip 1 character.
if ( * CurrentByte = = ' ? ' ) // Is it a double wildcard pattern?
+ + CurrentByte ; // If so skip the next space that will come up so we can reach the next byte.
Bytes . push_back ( - 1 ) ; // Push the byte back as invalid.
}
else
{
// https://stackoverflow.com/a/43860875/12541255
// Here we convert our string to a unsigned long integer. We pass our string then we use 16 as the base because we want it as hexadecimal.
// Afterwards we push the byte into our bytes vector.
Bytes . push_back ( std : : strtoul ( CurrentByte , & CurrentByte , 16 ) ) ;
}
}
return Bytes ;
} ;
ModuleSections textSection = GetSectionByName ( " .text " ) ; // Get the .text section.
if ( ! textSection . IsSectionValid ( ) )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-09 18:12:27 +02:00
2021-12-25 22:36:38 +01:00
ADDRESS stringAddress = FindAddressForString ( string , nullTerminator ) ; // Get Address for the string in the .rdata section.
2021-08-09 18:12:27 +02:00
if ( ! stringAddress )
2021-12-25 22:36:38 +01:00
return ADDRESS ( ) ;
2021-08-09 18:12:27 +02:00
std : : uint8_t * latestOccurence = nullptr ;
std : : ptrdiff_t occurencesFound = 0 ;
std : : uint8_t * StartOfCodeSection = reinterpret_cast < std : : uint8_t * > ( textSection . sectionStartAddress ) ; // Get the start of the .text section.
for ( DWORD i = 0ul ; i < textSection . sectionSize - 0x5 ; i + + )
{
byte byte = StartOfCodeSection [ i ] ;
if ( byte = = 0x8D ) // is it a LEA instruction?
{
2021-12-25 22:36:38 +01:00
ADDRESS skipOpCode = ADDRESS ( ( std : : uintptr_t ) & StartOfCodeSection [ i ] ) . OffsetSelf ( 0x2 ) ; // Skip next 2 opcodes, those being the instruction and then the register.
2021-08-09 18:12:27 +02:00
2021-12-25 22:36:38 +01:00
std : : int32_t relativeAddress = skipOpCode . GetValue < std : : int32_t > ( ) ; // Get 4-byte long string relative Address
2021-08-09 18:12:27 +02:00
std : : uintptr_t nextInstruction = skipOpCode . Offset ( 0x4 ) . GetPtr ( ) ; // Get location of next instruction.
2021-12-25 22:36:38 +01:00
ADDRESS potentialLocation = ADDRESS ( nextInstruction + relativeAddress ) ; // Get potential string location.
2021-08-09 18:12:27 +02:00
if ( potentialLocation = = stringAddress )
{
occurencesFound + + ; // Increment occurences found counter.
if ( occurence = = occurencesFound ) // Is it the occurence we want?
2021-12-25 22:36:38 +01:00
return ADDRESS ( & StartOfCodeSection [ i ] ) ; // If yes return it.
2021-08-09 18:12:27 +02:00
latestOccurence = & StartOfCodeSection [ i ] ; // Stash latest occurence.
}
}
}
2021-12-25 22:36:38 +01:00
return ADDRESS ( latestOccurence ) ;
2021-08-09 18:12:27 +02:00
}
2021-07-20 23:28:54 +02:00
std : : uintptr_t GetModuleBase ( )
{
return moduleBase ;
}
2021-08-09 18:12:27 +02:00
std : : string GetModuleName ( )
{
return moduleName ;
}
2021-07-20 23:28:54 +02:00
private :
std : : string moduleName = std : : string ( ) ;
std : : uintptr_t moduleBase = 0 ;
DWORD64 sizeOfModule = 0 ;
2021-08-09 18:12:27 +02:00
IMAGE_NT_HEADERS64 * ntHeaders = nullptr ;
IMAGE_DOS_HEADER * dosHeader = nullptr ;
std : : vector < ModuleSections > moduleSections = { } ;
2021-07-20 23:28:54 +02:00
} ;