Модификация бинарных файлов - PullRequest
0 голосов
/ 18 ноября 2009

Я пытаюсь написать небольшую программу, которая будет искать в двоичном файле несколько байтов и заменять их другой связкой байтов. Но каждый раз, когда я пытаюсь запустить это маленькое приложение, я получаю сообщение о istream_iterator не разыменовывается . Может быть, у кого-то есть предложение, как это сделать по-другому (итераторы для меня немного новая тема).

#include <fstream>
#include <iterator>
#include <algorithm>

using namespace std;

int main() {

typedef istream_iterator<char> input_iter_t;

const off_t SIZE = 4;
char before[SIZE] = { 0x12, 0x34, 0x56, 0x78 };
char  after[SIZE] = { 0x78, 0x12, 0x34, 0x65 };

fstream filestream("numbers.exe", ios::binary | ios::in | ios::out);

if (search(input_iter_t(filestream), input_iter_t(), before, before + SIZE) != input_iter_t()) {
    filestream.seekp(-SIZE, ios::cur);
    filestream.write(after, SIZE);
}

return 0;
}

Это моя вторая попытка сделать это, но что-то не так. С небольшими файлами выглядит нормально, но с большими (около 2 МБ) работает очень медленно и никогда не находит шаблон, который я ищу.

#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <windows.h>

using namespace std;

int main() {

const off_t Size = 4;
unsigned char before[Size] = { 0x12, 0x34, 0x56, 0x78 };
unsigned char  after[Size] = { 0x90, 0xAB, 0xCD, 0xEF };

    vector<char> bytes;
    {
        ifstream iFilestream( "numbers.exe", ios::in|ios::binary );
        istream_iterator<char> begin(iFilestream), end;
        bytes.assign( begin, end ) ;
    }

    vector<char>::iterator found = search( bytes.begin(), bytes.end(), before, before + Size );
    if( found != bytes.end() )
    {
        copy( after, after + Size, found );
        {
            ofstream oFilestream( "number-modified.exe" );
            copy( bytes.begin(), bytes.end(), ostream_iterator<unsigned char>(oFilestream) );
        }
    }
return 0;
}

Cheers, Thomas

Ответы [ 3 ]

1 голос
/ 18 ноября 2009

Считайте большую часть файла в память, замените его в памяти, а затем выгрузите пакет на диск. Чтение одного байта за раз очень медленно.

Я также предлагаю вам прочитать о mmap (или MapViewOfFile в win32).

0 голосов
/ 18 ноября 2009

Предполагая, что файл не слишком большой, просто прочитайте файл в память, затем измените буфер памяти по своему усмотрению, затем запишите его обратно в файл.

например. (Непроверенные):

FILE *f_in = fopen("inputfile","rb");
fseek(f_in,0,SEEK_END);

long size = ftell(f_in);
rewind(f_in);

char* p_buffer = (char*) malloc (size);
fread (p_buffer,size,1,f_in);
fclose(f_in);

unsigned char *p= (unsigned char*)p_buffer;

// process.

FILE *f_out = fopen("outoutfile","wb");
fwrite(p_buffer,size,1,f_out);
fclose(f_out);

free(p_buffer);
0 голосов
/ 18 ноября 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...