Files
l4d2-internal-base2/l4d2/utilities/module_info/module_info.cpp
2022-10-26 17:08:42 +08:00

148 lines
4.7 KiB
C++

#include "../lib.h"
Hikari::ModuleInfo_t::ModuleInfo_t(): _base_address( 0 ), _size( 0 ), _handle( nullptr )
{
}
Hikari::ModuleInfo_t::ModuleInfo_t( const std::string& module_name )
{
GetModuleInfo( module_name );
}
#ifdef WINDOWS
Hikari::ModuleInfo_t::ModuleInfo_t( const HMODULE handle )
{
GetModuleInfo( handle );
}
#endif
Hikari::ModuleInfo_t::~ModuleInfo_t()
{
this->_segments.clear();
this->_name.clear();
this->_base_address = this->_size = 0;
}
void Hikari::ModuleInfo_t::GetModuleInfo( const std::string& module_name )
{
#ifdef WINDOWS
const auto handle = GetModuleHandleA( module_name.c_str() );
if ( !handle )
throw std::runtime_error( std::format( ( "Failed to get module handle for {}" ), module_name ) );
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>( handle );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
throw std::runtime_error( std::format( ( "Invalid dos magic for {}" ), module_name ) );
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>( reinterpret_cast<std::uint8_t*>( handle ) + dos_header->e_lfanew );
if ( nt_header->Signature != IMAGE_NT_SIGNATURE )
throw std::runtime_error( std::format( ( "Invalid nt signature for {}" ), module_name ) );
this->_handle = handle;
this->_name = module_name;
this->_base_address = reinterpret_cast<uintptr_t>( handle );
this->_size = nt_header->OptionalHeader.SizeOfImage;
auto section = IMAGE_FIRST_SECTION( nt_header );
for ( auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++ )
{
const auto is_executable = ( section->Characteristics & IMAGE_SCN_MEM_EXECUTE ) != 0;
if ( const auto is_readable = ( section->Characteristics & IMAGE_SCN_MEM_READ ) != 0; is_executable && is_readable )
{
const auto start = reinterpret_cast<uintptr_t>( handle ) + section->VirtualAddress;
const auto size = ( std::min )( section->SizeOfRawData, section->Misc.VirtualSize );
this->_segments.emplace_back( start, reinterpret_cast<std::uint8_t*>( start ), size );
}
}
Logger->Success( std::format( ( "{} | base_addr:{:#09X} | size:{:#09X} | _segments.size():{}" ), _name, _base_address, _size, _segments.size() ) );
#else
// TODO: Linux support
#endif
}
#ifdef WINDOWS
void Hikari::ModuleInfo_t::GetModuleInfo( HMODULE handle )
{
if ( !handle )
throw std::runtime_error( std::format( ( "Invalid module handle" ) ) );
const auto dos_header = reinterpret_cast<PIMAGE_DOS_HEADER>( handle );
if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE )
throw std::runtime_error( std::format( ( "Invalid dos magic" ) ) );
const auto nt_header = reinterpret_cast<PIMAGE_NT_HEADERS>( reinterpret_cast<std::uint8_t*>( handle ) + dos_header->e_lfanew );
if ( nt_header->Signature != IMAGE_NT_SIGNATURE )
throw std::runtime_error( std::format( ( "Invalid nt signature" ) ) );
this->_handle = handle;
this->_name = ( "Hikari" );
this->_base_address = reinterpret_cast<uintptr_t>( handle );
this->_size = nt_header->OptionalHeader.SizeOfImage;
auto section = IMAGE_FIRST_SECTION( nt_header );
for ( auto i = 0; i < nt_header->FileHeader.NumberOfSections; i++, section++ )
{
if ( !strcmp( reinterpret_cast<char*>( section->Name ), ".text" ) )
{
const auto start = reinterpret_cast<uintptr_t>( handle ) + section->VirtualAddress;
const auto size = ( std::min )( section->SizeOfRawData, section->Misc.VirtualSize );
this->_segments.emplace_back( start, reinterpret_cast<std::uint8_t*>( start ), size, reinterpret_cast<const char*>( section->Name ) );
}
}
Logger->Success( std::format( ( "{} | base_addr:{:#09X} | size:{:#09X} | _segments.size():{}" ), _name, _base_address, _size, _segments.size() ) );
#else
// TODO: Linux support
#endif
}
std::string Hikari::ModuleInfo_t::Name()
{
return _name;
}
std::vector<Hikari::ModuleInfo_t::Segment_t>& Hikari::ModuleInfo_t::Segments()
{
return _segments;
}
std::uintptr_t Hikari::ModuleInfo_t::BaseAddress() const
{
return _base_address;
}
std::size_t Hikari::ModuleInfo_t::Size() const
{
return _size;
}
void* Hikari::ModuleInfo_t::Handle() const
{
return _handle;
}
FARPROC Hikari::ModuleInfo_t::GetProc( std::string_view proc_name )
{
if ( !this->_handle )
throw std::runtime_error( std::format( ( "Invalid module handle for {} when getting ProcAddress" ), this->_name ) );
#ifdef WINDOWS
if ( const auto address = GetProcAddress( this->_handle, proc_name.data() ); address )
{
return address;
}
#else
// TOOD: Linux support
#endif
return nullptr;
}