Pregunta

UPDATE

I solved it with the answer that's marked as valid, but with one slight difference. I open the file using fopen(file, "r+b"), not fopen(file, "r+"). The b opens it in binary mode, and doesn't screw up the file.


I was doing a simple program which I called "fuzzer".
This is my code:

int main(int argc, char* argv[]){
    // Here go some checks, such as argc being correct, etc.
    // ...

    // Read source file
    FILE *fSource;
    fSource = fopen(argv[1], "r+");
    if(fSource == NULL){
        cout << "Can't open file!";
        return 2;
    }

    // Loop source file
    char b;
    int i = 0;
    while((b = fgetc(fSource)) != EOF){
        b ^= 0x13;
        fseek(fSource, i++, SEEK_SET);
        fwrite(&b, 1, sizeof(b), fSource);
    }

    fclose(fSource);
    cout << "Fuzzed.";

    return 0;
}

However, it doesn't work. Before, I used while(!feof), but it didn't work either, and I saw that it's not correct, so I changed it to (b = fgetc()) != EOF (I suppose it's correct, right?).

When I run it, it gets stuck on an endless loop, and it doesn't modify the original file, but rather appends tildes to it (and the file quickly increases its size, until I stop it). If I change the open mode from "a+" to "r+", it simply deletes the contents of the file (but it at least doesn't get stuck in an endless loop).

Note: I understand that this isn't any kind of obfuscation or encryption. I'm not trying to encode files, just practicing with C++ and files.

¿Fue útil?

Solución

This code worked for me when tested on an Ubuntu 12.04 derivative with GCC 4.9.0:

#include <iostream>
#include <stdio.h>
using namespace std;

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
      cerr << "Usage: " << argv[0] << " file\n";
      return 1;
    }

    FILE *fSource = fopen(argv[1], "r+");
    if (fSource == NULL)
    {
        cerr << "Can't open file: " << argv[1] << "\n";
        return 2;
    }

    int c;
    int i = 0;
    while ((c = fgetc(fSource)) != EOF)
    {
        char b = c ^ 0x13;
        fseek(fSource, i++, SEEK_SET);
        fwrite(&b, 1, sizeof(b), fSource);
        fseek(fSource, i, SEEK_SET);
    }

    fclose(fSource);
    cout << "Fuzzed: " << argv[1] << "\n";

    return 0;
}

It reports file names; it reports errors to standard error (cerr); it uses int c; to read the character, but copies that to char b so that the fwrite() works. When run on (a copy of) its own source code, the first time the output looks like gibberish, and the second time recovers the original.

This loop, using fputc() instead of fwrite(), also works without needing the intermediate variable b:

    while ((c = fgetc(fSource)) != EOF)
    {
        fseek(fSource, i++, SEEK_SET);
        fputc(c ^ 0x13, fSource);
        fseek(fSource, i, SEEK_SET);
    }

The use of an fseek() after the read and after the write is mandated by the C standard. I'm not sure whether that's the main cause of your trouble, but it could in theory be one of the issues.

Otros consejos

You need int b;. A char can never be EOF. The manual describes all this. All in all, something like this:

for (int b, i = 0; (b = fgetc(fSource)) != EOF; ++i)
{
    unsigned char x = b;
    x ^= 0x13;
    fseek(fSource, i, SEEK_SET);
    fwrite(&x, 1, 1, fSource);
    fseek(fSource, i + 1, SEEK_SET);
}

You should also open the file with mode "rb+", and seek between each read and write (thanks @Jonathan Leffler).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top