C++ Make a Program Write Over Itself

ぐ巨炮叔叔 提交于 2019-12-24 12:57:35

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!