Posted
I have previously posted about this though I decided to improve the formatting and make some safety and good practice changes to the code.
also came up with a good name for it ( out of body function caller. get it? because of out of body experiences? ok cool )
#include <iostream>
#include <Windows.h>
#include <thread>
#include <vector>
#include <tuple>
typedef void( __stdcall* cextf_proto )( const std::uint32_t, const std::uint32_t );
enum calling_conventions : std::uint8_t
{
stdcall_,
cdecl_,
fastcall_
};
template< typename func_ret_t, calling_conventions ccv, typename... function_args >
void __stdcall call_ext_func( std::uint32_t function_address, std::uint32_t tuple_addr )
{
const auto function_args_tuples = *reinterpret_cast< std::tuple< function_args... > * >( tuple_addr );
switch ( ccv )
{
case calling_conventions::stdcall_:
{
typedef func_ret_t( __stdcall* stdcall_proc_func_proto )( function_args... );
const auto stdcall_proc_func = reinterpret_cast< stdcall_proc_func_proto >( function_address );
std::apply( stdcall_proc_func, function_args_tuples );
break;
}
case calling_conventions::cdecl_:
{
typedef func_ret_t( __cdecl* cdecl_proc_func_proto )( function_args... );
const auto cdecl_proc_func = reinterpret_cast< cdecl_proc_func_proto >( function_address );
std::apply( cdecl_proc_func, function_args_tuples );
break;
}
case calling_conventions::fastcall_:
{
typedef func_ret_t( __fastcall* fastcall_proc_func_proto )( function_args... );
const auto fastcall_proc_func = reinterpret_cast< fastcall_proc_func_proto >( function_address );
std::apply( fastcall_proc_func, function_args_tuples );
break;
}
}
}
std::vector< std::uint8_t > ret_function_instrs( void* function_address )
{
std::vector< std::uint8_t > function_bytes{ };
auto byte = static_cast< std::uint8_t* >( function_address );
do
{
function_bytes.push_back( *byte );
++byte;
} while ( *reinterpret_cast< std::uint32_t* >( byte ) != 0xCCCCCCCC );
return function_bytes;
}
void* alloc_func(void* func_address)
{
const auto function_instructions = ret_function_instrs( func_address );
const auto allocated_function = VirtualAlloc( nullptr, function_instructions.size( ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !allocated_function )
throw std::runtime_error( "failed to allocate memory for function." );
std::memcpy( allocated_function, function_instructions.data( ), function_instructions.size( ) );
return allocated_function;
}
template< typename... tuple_el >
void* alloc_tuple( std::tuple< tuple_el... > tuple )
{
const auto allocated_tuple = VirtualAlloc( nullptr, sizeof( tuple ), MEM_COMMIT, PAGE_EXECUTE_READWRITE );
if( !allocated_tuple )
throw std::runtime_error( "failed to allocate memory for tuple" );
std::memcpy( allocated_tuple, &tuple, sizeof( tuple ) );
return allocated_tuple;
}
void main_thread( HMODULE dll_module )
{
const auto base = reinterpret_cast< std::uint32_t >( GetModuleHandleA( nullptr ) );
constexpr auto function_rva = 0x1000;
constexpr auto arg_tuple = std::make_tuple< const char* >( { "exprssn" } );
const auto tuple = alloc_tuple( arg_tuple );
const auto caller_func_address = alloc_func( &call_ext_func< void, calling_conventions::cdecl_, const char* > );
const auto caller = static_cast< cextf_proto >( caller_func_address );
caller( base + function_rva, reinterpret_cast< std::uint32_t >( tuple ) );
FreeLibrary( dll_module );
}
bool __stdcall DllMain( HMODULE dll_module, const std::uint32_t reason_for_call, void* )
{
if ( reason_for_call == DLL_PROCESS_ATTACH )
std::thread{ &main_thread, dll_module }.detach( );
return true;
}
feel free to ask any questions in the replies!
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Replied
Man its sad no one vouches for expression its turning him more like depression ðŸ˜ðŸ˜ðŸ˜ðŸ˜
Also vouch since expression still expression my idk..
Cancel
Post
https://cdn.discordapp.com/attachments/661621789591470090/1013919752294498314/Untitled_1366_768_px_1546_202_px_2.gif
Added
Cancel
Post
Added
you mean the typedef void( __stdcall* cextf_proto )( const std::uint32_t, const std::uint32_t ); ?
there's no difference between doing static_cast< void( __stdcall* )( const std::uint32_t, const std::uint32_t ) > and static_cast< cextf_proto >
( also typedef void( __stdcall* cextf_proto )( const std::uint32_t, const std::uint32_t ) does not typedef a class )
it's the same thing except the former is cleaner.
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Users viewing this thread:
( Members: 0, Guests: 1, Total: 1 )
Cancel
Post