我无法弄清楚为什么架子无法正确填充我的缓冲区。 CS50恢复

发布于 2025-01-22 04:01:37 字数 2171 浏览 2 评论 0原文

我已经在GDB中撕下了此代码数小时。我知道fread正在返回适当的字节数(512)。甚至检查了$ eax打印以确认。有人有可能有人暗示我的逻辑有什么问题吗?

我认为标题可能会从文件的开头偏移,因此我认为在第一次读取字节时,请查找hex匹配,并设置fseek可以解决问题。没有这样的运气。打印匹配结果是0

#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t       BYTE;
typedef enum { false, true } boolean;

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    char *infile = argv[optind];
    char *fileName = "image";

    FILE *rawData = fopen(infile, "r");
    FILE *imgJPG  = fopen(fileName, "w");
    int match  = 0;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    BYTE *FATbuffer = (BYTE *)malloc(sizeof(BYTE) * 512);

    if (rawData == NULL)
    {
        printf("Error processing file. Exiting...");
        return 1;
    }

    // begin reading raw data and writing it to buffer
    while (fread(FATbuffer, sizeof(BYTE), 512, rawData) == 512)
    {
        if (imgCnt == 0)
        {
            for (int c = 0; c < 512; c++)
            {
                if (FATbuffer[c + 0] == 0xff &&
                    FATbuffer[c + 1] == 0x8d &&
                    FATbuffer[c + 2] == 0xff)
                {
                    fseek(rawData, c, SEEK_SET);
                    imgCnt++;
                    match++;
                }
            }
        }
        else
        {
            if (FATbuffer[0] == 0xff &&
                FATbuffer[1] == 0x8d &&
                FATbuffer[2] == 0xff &&
                imgCnt > 0)
            {
                sprintf(fileName, "%d.jpg", imgCnt);
                fclose(imgJPG);
                imgCnt++;
            }

            if (imgJPG == NULL)
            {
                printf("Error processing file. Exiting...");
                return 3;
            }

            fwrite(FATbuffer, sizeof(BYTE), 512, imgJPG);
        }
    }

    printf("%d\n", match);
    // file processed, free memory
    free(FATbuffer);
    return 0;
}

I've torn through this code in gdb for hours. I know that fread is returning the appropriate amount of bytes (512). Even checked the $eax print to confirm. Is there any chance someone may be able to give me a hint at what's wrong with my logic?

I thought that the headers may be offset from the beginning of the file, so I figured on first read going through byte by byte looking for the hex match and setting fseek would do the trick. No such luck. Printing match results in a 0.

#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

typedef uint8_t       BYTE;
typedef enum { false, true } boolean;

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    char *infile = argv[optind];
    char *fileName = "image";

    FILE *rawData = fopen(infile, "r");
    FILE *imgJPG  = fopen(fileName, "w");
    int match  = 0;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    BYTE *FATbuffer = (BYTE *)malloc(sizeof(BYTE) * 512);

    if (rawData == NULL)
    {
        printf("Error processing file. Exiting...");
        return 1;
    }

    // begin reading raw data and writing it to buffer
    while (fread(FATbuffer, sizeof(BYTE), 512, rawData) == 512)
    {
        if (imgCnt == 0)
        {
            for (int c = 0; c < 512; c++)
            {
                if (FATbuffer[c + 0] == 0xff &&
                    FATbuffer[c + 1] == 0x8d &&
                    FATbuffer[c + 2] == 0xff)
                {
                    fseek(rawData, c, SEEK_SET);
                    imgCnt++;
                    match++;
                }
            }
        }
        else
        {
            if (FATbuffer[0] == 0xff &&
                FATbuffer[1] == 0x8d &&
                FATbuffer[2] == 0xff &&
                imgCnt > 0)
            {
                sprintf(fileName, "%d.jpg", imgCnt);
                fclose(imgJPG);
                imgCnt++;
            }

            if (imgJPG == NULL)
            {
                printf("Error processing file. Exiting...");
                return 3;
            }

            fwrite(FATbuffer, sizeof(BYTE), 512, imgJPG);
        }
    }

    printf("%d\n", match);
    // file processed, free memory
    free(FATbuffer);
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挽你眉间 2025-01-29 04:01:37

代码中存在多个问题:

  • 您应该测试是否有命令行参数(处理选项后,您可能要删除用于发布的代码)。

  • 必须以二进制模式打开文件,以避免翻译的潜在末端。

  • 您应该延迟打开imgjpg直到找到JPG标头。

  • 无需分配fatbuffer,定义具有自动存储的512字节数组是可以的。

  • 您一次扫描JPG签名一个块,但是如果它跨越512字节边界,您可能会错过签名,并且您可以在fatbuffer array时访问2个字节。 > c 大于509。

  • fseek(rawdata,c,seek_set);设置文件位置从数组开始的开头,而不是从文件的开头设置。<<<<<<<<<<<<<<<<<<< /p>

  • sprintf(文件名,“%d.jpg”,imgcnt);尝试覆盖字符串常数。这具有不确定的行为。您可能的意思是:

      char fileName [64];
      snprintf(文件名,sizeof fileName,“ image%d.jpg”,imgcnt);
      file *imgjpg = fopen(文件名,“ wb”);
     

这是一个修改版本,可以提取数据流中任何地方嵌入的JPG文件:

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    if (optind >= argc)
        return 1;
    char *infile = argv[optind];
    FILE *rawData = fopen(infile, "rb");  // open the disk image
    char fileName[64];
    FILE *imgJPG = NULL;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    // add an extra 2 bytes to match signature across sector boundaries
    uint8_t FATbuffer[514];

    // begin reading raw data into buffer
    int pos = 2;
    while (fread(FATbuffer + 2, 1, 512, rawData) == 512) {
        for (int c = pos; c < 512; c++) {
            if (FATbuffer[c + 0] == 0xff &&
                FATbuffer[c + 1] == 0x8d &&
                FATbuffer[c + 2] == 0xff) {
                // found signature: skip to a new file
                if (imgJPG) {
                    // write the end of the current image
                    fwrite(FATbuffer + pos, c - pos, 1, imgJPG);
                    fclose(imgJPG);
                }
                pos = c;
                imgCnt++;
                snprintf(fileName, sizeof fileName, "image%d.jpg", imgCnt);
                imgJPG = fopen(fileName, "wb");
                if (imgJPG == NULL) {
                    fprintf(stderr, "Cannot create file %s: %s\n",
                            fileName, strerror(errno));
                    return 3;
                }
            }
        }
        if (imgJPG) {
            // write end of block to current image
            fwrite(FATbuffer + pos, 512 - pos, 1, imgJPG);
        }
        // copy the last 2 bytes to test for signature overlapping blocks
        FATbuffer[0] = FATbuffer[512];
        FATbuffer[1] = FATbuffer[513];
        // uncopied file data starts a 0 now.
        pos = 0;
    }
    if (imgJPG) {
        // write last 2 bytes to current image
        fwrite(FATbuffer, 2, 1, imgJPG);
        fclose(imgJPG);
    }
    printf("%d\n", imgCnt != 0);
    printf("%d images extracted\n", imgCnt);
    return 0;
}

如果您可以假设签名处于扇区的开头,则可以简化代码:

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    if (optind >= argc)
        return 1;
    char *infile = argv[optind];
    FILE *rawData = fopen(infile, "rb");  // open the disk image
    char fileName[64];
    FILE *imgJPG = NULL;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    uint8_t FATbuffer[512];

    // begin reading raw data into buffer
    while (fread(FATbuffer, 1, 512, rawData) == 512) {
        if (FATbuffer[c + 0] == 0xff &&
            FATbuffer[c + 1] == 0x8d &&
            FATbuffer[c + 2] == 0xff) {
            // found signature: skip to a new file
            if (imgJPG) {
                fclose(imgJPG);
            }
            imgCnt++;
            snprintf(fileName, sizeof fileName, "image%d.jpg", imgCnt);
            imgJPG = fopen(fileName, "wb");
            if (imgJPG == NULL) {
                fprintf(stderr, "Cannot create file %s: %s\n",
                        fileName, strerror(errno));
                return 3;
            }
        }
        if (imgJPG) {
            // write end of block to current image
            fwrite(FATbuffer, 512, 1, imgJPG);
        }
    }
    if (imgJPG) {
        fclose(imgJPG);
    }
    printf("%d\n", imgCnt != 0);
    printf("%d images extracted\n", imgCnt);
    return 0;
}

There are multiple problems in your code:

  • you should test if a command line argument is available (after handling options, code you probably removed for posting).

  • files must be open in binary mode to avoid potential end of translation.

  • you should delay opening imgJPG until you have found the JPG header.

  • there is no need to allocate FATbuffer, defining a 512 byte array with automatic storage is fine.

  • you scan for the JPG signature one block at a time, but you might miss the signature if it spans a 512 byte boundary and you access 2 bytes beyond the end of the FATbuffer array when c is greater than 509.

  • fseek(rawData, c, SEEK_SET); set the file position at the offset from the beginning of the array, not from the beginning of the file.

  • sprintf(fileName, "%d.jpg", imgCnt); attempts to overwrite a string constant. This has undefined behavior. You probably meant this:

      char fileName[64];
      snprintf(fileName, sizeof fileName, "image%d.jpg", imgCnt);
      FILE *imgJPG = fopen(fileName, "wb");
    

Here is a modified version that can extract JPG files embedded anywhere in a data stream:

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    if (optind >= argc)
        return 1;
    char *infile = argv[optind];
    FILE *rawData = fopen(infile, "rb");  // open the disk image
    char fileName[64];
    FILE *imgJPG = NULL;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    // add an extra 2 bytes to match signature across sector boundaries
    uint8_t FATbuffer[514];

    // begin reading raw data into buffer
    int pos = 2;
    while (fread(FATbuffer + 2, 1, 512, rawData) == 512) {
        for (int c = pos; c < 512; c++) {
            if (FATbuffer[c + 0] == 0xff &&
                FATbuffer[c + 1] == 0x8d &&
                FATbuffer[c + 2] == 0xff) {
                // found signature: skip to a new file
                if (imgJPG) {
                    // write the end of the current image
                    fwrite(FATbuffer + pos, c - pos, 1, imgJPG);
                    fclose(imgJPG);
                }
                pos = c;
                imgCnt++;
                snprintf(fileName, sizeof fileName, "image%d.jpg", imgCnt);
                imgJPG = fopen(fileName, "wb");
                if (imgJPG == NULL) {
                    fprintf(stderr, "Cannot create file %s: %s\n",
                            fileName, strerror(errno));
                    return 3;
                }
            }
        }
        if (imgJPG) {
            // write end of block to current image
            fwrite(FATbuffer + pos, 512 - pos, 1, imgJPG);
        }
        // copy the last 2 bytes to test for signature overlapping blocks
        FATbuffer[0] = FATbuffer[512];
        FATbuffer[1] = FATbuffer[513];
        // uncopied file data starts a 0 now.
        pos = 0;
    }
    if (imgJPG) {
        // write last 2 bytes to current image
        fwrite(FATbuffer, 2, 1, imgJPG);
        fclose(imgJPG);
    }
    printf("%d\n", imgCnt != 0);
    printf("%d images extracted\n", imgCnt);
    return 0;
}

If you can assume the signature to be at the start of a sector, the code can be simplified:

#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    // get filenames from cml input and open file
    if (optind >= argc)
        return 1;
    char *infile = argv[optind];
    FILE *rawData = fopen(infile, "rb");  // open the disk image
    char fileName[64];
    FILE *imgJPG = NULL;
    int imgCnt = 0;

    // buffer to hold 512 bytes of file data - FAT file system
    uint8_t FATbuffer[512];

    // begin reading raw data into buffer
    while (fread(FATbuffer, 1, 512, rawData) == 512) {
        if (FATbuffer[c + 0] == 0xff &&
            FATbuffer[c + 1] == 0x8d &&
            FATbuffer[c + 2] == 0xff) {
            // found signature: skip to a new file
            if (imgJPG) {
                fclose(imgJPG);
            }
            imgCnt++;
            snprintf(fileName, sizeof fileName, "image%d.jpg", imgCnt);
            imgJPG = fopen(fileName, "wb");
            if (imgJPG == NULL) {
                fprintf(stderr, "Cannot create file %s: %s\n",
                        fileName, strerror(errno));
                return 3;
            }
        }
        if (imgJPG) {
            // write end of block to current image
            fwrite(FATbuffer, 512, 1, imgJPG);
        }
    }
    if (imgJPG) {
        fclose(imgJPG);
    }
    printf("%d\n", imgCnt != 0);
    printf("%d images extracted\n", imgCnt);
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文