C++ 使程序重写自身 [英] C++ Make a Program Write Over Itself

查看:24
本文介绍了C++ 使程序重写自身的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几天前我发布了一个关于类似主题的问题(和几年前的一个),但我决定继续开始.我正在尝试将 C++ 代码注入 C++ 代码(以某种可移植的方式使用不使用操作系统特定功能并尝试独立于编译器/工具链的方式).我基本上想这样做是为了尝试执行运行时 C++ 脚本.我写了一个小测试程序(它真的只是有点乱七八糟的):Main.cpp:

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;
}

源.cpp:

extern "C"
{
    int calc()
    {
        int q = 30 * 123;
        for( int i = 0; i < 10; ++i )
            q *= i;
        return q;
    }
}

基本上我只是尝试用 malloc 和 new 分配一大块内存,但我想也许我可以覆盖已经专用于进程内存的内存(这就是为什么我有 test 指向的函数 em>cmpp 并尝试覆盖它).但是我收到写访问错误.我查看了这篇文章 和其中一个答案 似乎可以在没有访问冲突的情况下覆盖程序自己的内存(这就是我想要做的),错误不少.有人可以详细说明这一点,并告诉我如何在不使用任何非标准功能(或至少可以/被抽象掉的功能)的情况下以某种可移植的方式做到这一点?

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)?

推荐答案

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

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.

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

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.

这篇关于C++ 使程序重写自身的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆