C++ C++;使一个程序重写它自己

C++ C++;使一个程序重写它自己,c++,reflection,architecture,code-injection,runtime-compilation,C++,Reflection,Architecture,Code Injection,Runtime Compilation,几天前我发布了一篇文章(),但我决定继续并开始。我试图将C++代码注入到C++代码中(以某种可移植的方式使用没有OS特定的特性,并试图成为编译器/工具链无关的方式)。我基本上想做这件事,试图做运行时C++脚本。我写了一个小的测试程序(它实际上有点杂乱无章):Main.cpp: #include <stdlib.h> #include <iostream> #include <fstream> #include <string> #include &

几天前我发布了一篇文章(),但我决定继续并开始。我试图将C++代码注入到C++代码中(以某种可移植的方式使用没有OS特定的特性,并试图成为编译器/工具链无关的方式)。我基本上想做这件事,试图做运行时C++脚本。我写了一个小的测试程序(它实际上有点杂乱无章):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;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
constexpr char hexmap[]={'0','1','2','3','4','5','6','7',
‘8’、‘9’、‘a’、‘b’、‘c’、‘d’、‘e’、‘f’};
字符串HexStr(无符号字符*数据,整数长度)
{
std::字符串s(len*2',);
对于(int i=0;i>4];
s[2*i+1]=hexmap[data[i]&0x0F];
}
返回s;
}
/*我知道有一个标准GC,这是
绝不是生产*/
模板
结构垃圾收集器
{
std::向量ts;
GarbageCollector()=默认值;
~GarbageCollector(){
对于(T*i:ts)
删除i;
}
};
模板
结构垃圾收集器
{
std::向量ts;
GarbageCollector()=默认值;
~GarbageCollector(){
对于(T*i:ts)
删除[]i;
}
};
std::tupleReadBinaryBuffer(
字符串文件名,垃圾收集器*gc)
{
std::ifstream二进制数据;
binaryData.open(“Source.obj”,std::ios::binary);
if(binaryData.fail()){
标准::cerr ts.push_back(缓冲区);
返回{buffer,i};
}
std::string ReadBinary(std::string文件名)
{
垃圾收集器gc;
自动结果=ReadBinaryBuffer(文件名,&gc);
字符串缓冲区;
赋值(std::get<0>(结果),std::get<1>(结果));
返回字符串缓冲区;
}
std::string ReadBinary(std::tuplebufferContainer)
{
字符串缓冲区;
stringBuffer.assign(std::get<0>(bufferContainer),
std::get<1>(bufferContainer));
返回字符串缓冲区;
}
外部“C”
{
int测试(){
返回3;
}
int(*cmpp)();
}
int main(int argc,char*args)
{
cmpp=&test;
auto binary=ReadBinary(“Source.obj”);
自动函数=二进制.substr(347,56);
const char*code=function.c_str();
std::cout>关闭;
返回0;
}
Source.cpp:

extern "C"
{
    int calc()
    {
        int q = 30 * 123;
        for( int i = 0; i < 10; ++i )
            q *= i;
        return q;
    }
}
extern“C”
{
int calc()
{
int q=30*123;
对于(int i=0;i<10;++i)
q*=i;
返回q;
}
}

基本上,我试着用malloc和new分配一大块内存,但我想也许我可以覆盖已经专用于进程内存的内存(这就是为什么我让cmpp指向函数测试并尝试覆盖它)。但是,我遇到了一个写访问错误。我查看了其中一个,并从中发现,可以覆盖程序自己的内存,而不会发生访问冲突(这就是我想要做的)请有人详细说明一下,并告诉我如何在不使用任何非标准功能(或至少一个可以/被抽象掉的功能)的情况下,以某种可移植的方式执行此操作?

默认情况下,您的程序将加载到只读和执行内存中,不允许写入(至少在任何现代操作系统上)。不同的保护是出于安全原因,如果有人破坏了你的软件,他们不应该对你这样做,例如泄露信息

此请求存储在二进制文件中,由链接器完成。您可以将链接器更改为请求将程序加载到可写内存中,但这远远不是最佳的,也不可移植


更好的方法是从您的操作系统请求一个可执行和可写的页面(linux上的mmap等),但据我所知,也没有可移植的方法来实现这一点。

谢谢您的回复,我很感激!)对于作为单个翻译单元的程序,该如何处理?链接器不会正确使用?链接器仍将被使用。有外部代码,如C运行时(gcc上的glibc,Windows上的VC++运行时等)并将任何只读数据链接到具有相应权限的页面中,等等。您仍然可以通过请求来完成此操作。文本可以通过请求链接器写入,但由于它的大小不会增加,如果您想要更多空间,则必须稍后分配。