使用fgetc / fwrite进行简单的字节更改失败

时间:2014-05-10 00:35:04

标签: c++ file fopen fwrite

更新

我用“有效”标记的答案解决了这个问题,但略有不同。我使用fopen(file, "r+b")而不是fopen(file, "r+")打开文件。 b以二进制模式打开它,并且不会搞砸文件。


我正在做一个简单的程序,我打电话给#34; fuzzer" 这是我的代码:

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

但是,它不起作用。之前,我使用了while(!feof),但它也没有工作,I saw that it's not correct,所以我将其更改为(b = fgetc()) != EOF(我认为它是正确的,对吧?) 。

当我运行它时,它会卡在无限循环上,并且它不会修改原始文件,而是向它添加波形(并且文件会快速增加其大小,直到我停止它)。如果我从&#34; a +&#34;更改开放模式到&#34; r +&#34;,它只是删除文件的内容(但它至少不会陷入无限循环)。

注意:我知道这不是任何混淆或加密。我没有尝试编码文件,只是练习使用C ++和文件。

2 个答案:

答案 0 :(得分:2)

在使用GCC 4.9.0的Ubuntu 12.04衍生产品上测试时,此代码对我有用:

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

报告文件名;它将错误报告给标准错误(cerr);它使用int c;来阅读该字符,但将其复制到char b以便fwrite()正常工作。当运行(自己的)源代码的副本时,第一次输出看起来像乱码,第二次恢复原始。

此循环使用fputc()代替fwrite(),也可以在不需要中间变量b的情况下运行:

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

在C标准强制要求在写入之后使用fseek()。我不确定这是否是您遇到麻烦的主要原因,但理论上它可能是其中一个问题。

答案 1 :(得分:1)

您需要int b;char永远不会是EOFThe manual描述了这一切。总而言之,这样的事情:

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

您还应该使用模式"rb+"打开文件,并在每次读写之间进行搜索(感谢@Jonathan Leffler)。