问题
I posted a question on a similar topic a couple days ago (and one a couple years ago), but I decided to go ahead and get started. I am trying to inject C++ code into C++ code (in a somewhat portable manner using no os specific features and trying to be compiler/toolchain independent manner). I basically want to do this in an attempt to do runtime C++ scripts. I wrote a small test program (its really just kinda thrown together and hacky): Main.cpp:
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <sstream>
#include <vector>
#include <tuple>
constexpr char hexmap[] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
std::string HexStr( unsigned char *data, int len )
{
std::string s( len * 2, ' ' );
for( int i = 0; i < len; ++i ) {
s[ 2 * i ] = hexmap[ ( data[ i ] & 0xF0 ) >> 4 ];
s[ 2 * i + 1 ] = hexmap[ data[ i ] & 0x0F ];
}
return s;
}
/*I am aware there is a standard GC and that this is
by no means production.*/
template< typename T, unsigned short ARRAY >
struct GarbageCollector
{
std::vector< T* > ts;
GarbageCollector() = default;
~GarbageCollector() {
for( T* i : ts )
delete i;
}
};
template< typename T >
struct GarbageCollector< T, 1 >
{
std::vector< T* > ts;
GarbageCollector() = default;
~GarbageCollector() {
for( T* i : ts )
delete[] i;
}
};
std::tuple< char*, std::streamoff > ReadBinaryBuffer(
std::string fileName, GarbageCollector< char, 1 >* gc )
{
std::ifstream binaryData;
binaryData.open( "Source.obj", std::ios::binary );
if( binaryData.fail() ) {
std::cerr << "Failed to open file!\n";
return { "Failed to open file!\n", 1 };
}
binaryData.seekg( 0, std::ios::end );
std::streamoff i = binaryData.tellg();
char* buffer = new char[ i ];
binaryData.seekg( 0, std::ios::beg );
binaryData.read( buffer, i );
binaryData.close();
gc->ts.push_back( buffer );
return { buffer, i };
}
std::string ReadBinary( std::string fileName )
{
GarbageCollector< char, 1 > gc;
auto result = ReadBinaryBuffer( fileName, &gc );
std::string stringBuffer;
stringBuffer.assign( std::get< 0 >( result ), std::get< 1 >( result ) );
return stringBuffer;
}
std::string ReadBinary( std::tuple< char*,
std::streamoff > bufferContainer )
{
std::string stringBuffer;
stringBuffer.assign( std::get< 0 >( bufferContainer ),
std::get< 1 >( bufferContainer ) );
return stringBuffer;
}
extern "C"
{
int test() {
return 3;
}
int( *cmpp )();
}
int main( int argc, char* args )
{
cmpp = &test;
auto binary = ReadBinary( "Source.obj" );
auto function = binary.substr( 347, 56 );
const char* code = function.c_str();
std::cout << HexStr( ( unsigned char* ) ( code ), function.size() );
//strcpy( ( char* )cmpp, ( ( char* ) code ) );
char* testp = ( char* ) cmpp;
char* testpp = ( char* ) code;
for( size_t i = 0; i < 54; ++i ) {
*testp++ = *testpp++;
}
cmpp();
char close;
std::cin >> close;
return 0;
}
Source.cpp:
extern "C"
{
int calc()
{
int q = 30 * 123;
for( int i = 0; i < 10; ++i )
q *= i;
return q;
}
}
Basically I tried just allocating a hunk of memory with malloc and new, but I thought maybe I could overwrite memory already dedicated to process memory (which is why I have the function test pointed at by cmpp and try to overwrite it). However I get a write access error. I took a look at this post and from one of the answers seems that it is possible to overwrite the programs own memory without an access violation (which is what I want to do), by mistake no less. Could someone elaborate on this please and tell me how to do this in possible a somewhat portable manner without using any non - standard feature (or at least one that can be/is abstracted away)?
回答1:
By default, your program will be loaded into read and execute only memory, no writing allowed (at least on any modern operating system). The different protections are for security reasons, if someone breaks your software, they shouldn't be able to do this to you and for example leak information.
This request is stored inside the binary and is done by the linker. You may be able to change your linker to request for your program to be loaded into writable memory, but this would be far from optimal and also not portable.
A better approach would be to request an executable and writable page from your operating system (mmap
et al on linux), but there is no portable way to do this either as far as I am aware.
来源:https://stackoverflow.com/questions/50165795/c-make-a-program-write-over-itself