tags:

views:

134

answers:

3

Hi guys,

I'm trying to write a small program which will search a binary file for a few bytes and replace these with another bunch of bytes. But everytime I try running this small app I got message about *istream_iterator is not dereferenceable*. Maybe someone have a suggestion how to do this in another way (iterators are a little bit a new subject for me).

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

This is my second attempt to do this but also something is wrong. With small files looks like works OK but with bigger (around 2MB) it works very slowly and never find pattern what I'm looking for.

#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

+1  A: 

Read a larger part of the file to memory, replace it in memory and then dump the bunch to the disk. Reading one byte at a time is very slow.

I also suggest you read about mmap (or MapViewOfFile in win32).

elcuco
A: 

search won't work on an istream_iterator because of the nature of the iterator. It's an input iterator, which means it simply moves forward - this is because it reads from the stream, and once it's read from the stream, it can't go back. search requires a forward iterator, which is an input iterator where you can stop, make a copy, and move one forward while keeping the old one. An example of a forward iterator is a singly-linked list. You can't go backwards, but you can remember where you are and restart from there.

The speed issue is because vector is truly terrible at handling unknown data. Every time it runs out of room, it copies the whole buffer over to new memory. Replace it with a deque, which can handle data arriving one by one. You will also likely get improved performance trying to read from the stream in blocks at a time, as character-by-character access is a pretty bad way to load an entire file into memory.

coppro
A: 

Assuming the file isn't too large, just read the file into memory, then modify the memory buffer as you see fit, then write it back out to a file.

E.g. (untested):

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);
jon hanson