Posted
Let's say you want to copy a function at runtime, you may think of just copy and pasting the function by looping through it, finding the end, and then just allocating memory for it and boom std::memcpy comes to make it easy for you.
Well, this would be a good idea, if functions used absolute address calls every time they want to call a function, which isn't the case.
Most CALLs and JMPs you see, take relative addresses as operands. That means there's a calculation that occurs in order to make the JMP / CALL which binds it to be relative to the current location in memory of the IP ( instruction pointer ).
Today I'll be going over that calculation and I'll be showing you how to properly copy a function.
The CALL / JMP formula goes as following: target absolute address - address of the instruction after the relative CALL / JMP instruction.
Seems simple right? That's because it is.
Now, you may see why this becomes an issue when copy and pasting functions, that same relative address is never changed, which means when we try to call a copied function that had relative JMPs or CALLs in it ( which is quite often, I'd say around 95-99% of the time lol )
without fixing the relative addresses, we're guaranteed to crash.
Here's my implementation of how to recalculate and fix relative addresses when copying functions with commented code to further explain:
#include <iostream>
#include <Windows.h>
#include <thread>
#include <vector>
#include <array>
#include <unordered_map>
std::vector< std::uint8_t > ret_function_bytes( void* address )
{
auto byte = static_cast< std::uint8_t* >( address );
std::vector< std::uint8_t > function_bytes{ };
static const std::unordered_map< std::uint8_t, std::uint8_t > ret_bytes_map
{
{
0xC2,
0x03
},
{
0xC3,
0x01
}
};
static const auto alignment_bytes = std::to_array< std::uint8_t >
(
{ 0xCC, 0x90 }
);
while( true )
{
function_bytes.push_back( *byte );
for( const auto& ret_byte : ret_bytes_map )
{
const auto& [ opcode, opcode_sz ] = ret_byte;
if( *byte == opcode )
{
for( const auto& alignment_byte : alignment_bytes )
{
if( *( byte + opcode_sz ) == alignment_byte )
return function_bytes;
}
}
}
++byte;
}
}
void* copy_function( void* function_address )
{
// MSVC specific way of copying functions. not standardized.
const auto function_instrs = ret_function_bytes( function_address );
// throw exception in case virtualalloc fails
const auto allocated_func_mem = VirtualAlloc( nullptr, function_instrs.size( ), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
if( !allocated_func_mem )
throw std::runtime_error( "failed to allocate memory for function" );
// relative calls address re-calculation adjusted for the "new" memory location of the function.
for( auto it = function_instrs.begin( ); it < function_instrs.end( ); ++it )
{
if( *it == 0xE9 || *it == 0xE8 )
{
// getting the offset of bytes from the beginning of the function
// so we can add it later to get the next instruction address
// of both the original function and our new function.
const auto dist = std::distance( function_instrs.begin( ), it );
// old offset used by the old function to make a relative CALL or JMP
const auto o_rel_offset = *reinterpret_cast< std::uint32_t* >( it._Ptr + 1 );
// the address of the instruction after the relative CALL instruction
const auto o_next_instr = reinterpret_cast< std::uint32_t >( function_address ) + dist + 5;
// absolute address of the callee
const auto callee_abs_address = o_next_instr + o_rel_offset;
// same as before except it's the next instruction of the new function
const auto next_instr = reinterpret_cast< std::uint32_t >( allocated_func_mem ) + dist + 5;
// relative address calculation
const auto rel_addr = callee_abs_address - next_instr;
// setting the new relative address operand value
*reinterpret_cast< std::uint32_t* >( it._Ptr + 1 ) = rel_addr;
}
}
// copying the new function with the fixed relative addresses to our allocated memory for it
std::memcpy( allocated_func_mem, function_instrs.data( ), function_instrs.size( ) );
return allocated_func_mem;
}
void main_thread( HMODULE dll_module )
{
const auto base = reinterpret_cast< std::uint32_t >( GetModuleHandleA( nullptr ) );
constexpr auto function_rva = 0x1030;
const auto new_func_address = copy_function( reinterpret_cast< void* >( base + function_rva ) );
const auto new_func = static_cast< void( __cdecl * )( const char* ) >( new_func_address );
std::printf( "%p\n", new_func );
new_func( "exprssn is godly\n" );
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;
}
https://github.com/expressiongz/runtime-copy-function
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
Replied
expression literally became the god of C++ in the forum :kekw:
Cancel
Post
Random quote here...
Replied
I'm not reading this lmao but I'll comment so it gets boosted
Cancel
Post
https://media.discordapp.net/attachments/1064332722065117204/1067596913781784606/Frame_2_1.png
Replied
vouch my guy expression is turning into depression if u do not vouch..
Cancel
Post
https://cdn.discordapp.com/attachments/661621789591470090/1013919752294498314/Untitled_1366_768_px_1546_202_px_2.gif
Random quote here...
Replied
@VoidableMethod Bro what you said is absolutely cringe... Expression is good at what he likes to do. But you cant call him a god over this â˜
Cancel
Post
https://cdn.discordapp.com/attachments/661621789591470090/1013919752294498314/Untitled_1366_768_px_1546_202_px_2.gif
Replied
@pepsi I'm just saying he's really good at it. I never said he should stop or is bad at it...
Cancel
Post
Random quote here...
https://cdn.discordapp.com/attachments/661621789591470090/1013919752294498314/Untitled_1366_768_px_1546_202_px_2.gif
Replied
https://github.com/expressiongz/out-of-body-function-caller/blob/main/dllmain.cpp
It'd be something like this
Cancel
Post
https://media.discordapp.net/attachments/1044764388546068510/1051935933836050482/Signature_4.png
"Questionable intellegence, but I like the mystery" - CubeFaces
https://cdn.discordapp.com/attachments/1136067487847415848/1138948596679589898/sig.png
Random quote here...
Users viewing this thread:
( Members: 0, Guests: 0, Total: 0 )
Cancel
Post