C ++ делает программу перезаписывающей себя - PullRequest
0 голосов
/ 04 мая 2018

Я опубликовал вопрос на аналогичную тему пару дней назад ( и один пару лет назад ), но я решил пойти дальше и начать. Я пытаюсь внедрить код C ++ в код C ++ (несколько портативным способом, не используя никаких специфических функций ОС и пытаясь быть независимым от компилятора / цепочки инструментов). Я в основном хочу сделать это в попытке сделать сценарии 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;
}

Source.cpp:

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

В основном я пытался выделить часть памяти с помощью malloc и new, но я подумал, что, возможно, я мог бы перезаписать память, уже выделенную для памяти процесса (именно поэтому у меня есть функция test , на которую указывает cmpp и попробуйте перезаписать его). Однако я получаю ошибку доступа для записи. Я посмотрел на этот пост и из одного из ответов кажется, что можно перезаписать программы собственной памяти без нарушения прав доступа (что Хочу сделать) по ошибке не меньше. Может ли кто-нибудь уточнить это, пожалуйста, и скажите мне, как сделать это, возможно, несколько портативным способом без , используя любую нестандартную функцию (или хотя бы одну, которая может быть удалена / удалена)?

1 Ответ

0 голосов
/ 04 мая 2018

По умолчанию ваша программа будет загружена в память только для чтения и выполнения, запись не разрешена (по крайней мере, в любой современной операционной системе). Различные меры защиты по соображениям безопасности: если кто-то взломает ваше программное обеспечение, он не сможет сделать это с вами и, например, получить утечку информации.

Этот запрос хранится в двоичном файле и выполняется компоновщиком. Вы можете изменить компоновщик так, чтобы он запрашивал загрузку вашей программы в доступную для записи память, но это было бы далеко не оптимально, а также не переносимо.

Лучшим подходом было бы запросить исполняемую и доступную для записи страницу из вашей операционной системы (mmap и др. В linux), но, насколько я знаю, не существует переносимого способа сделать это.

...