Home > Blockchain >  C recover compiles but return null for the files read
C recover compiles but return null for the files read

Time:12-09

Trying to solve this problem i keep finding the same errors:

:) recover.c exists.

:) recover.c compiles.

:) handles lack of forensic image

:( recovers 000.jpg correctly 000.jpg not found

:( recovers middle images correctly 001.jpg not found

:( recovers 049.jpg correctly 049.jpg not found

That makes me think that the files are not been read or opened at all and i can't find why because the code compiles.

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

int main(int argc, char* argv[])
{
    //checks if there is an input
    if (argc != 2)
    {
        printf("./recover Usage: ./recover image \n");
        return 1;
    }
    else
    {
        char* filename = argv[1];
        FILE* input = fopen(filename, "r");

        if (strcmp(filename, "card.raw") != 0)
        {
            printf("Unable to open: %s\n", filename);
            return 2;
        }
        else
        {
            //Create buffer
            uint8_t buffer[512];

            //Create pointer for the buffer
            FILE* output = NULL;

            // create 8 bytes file
            char files[8];

            //Files counters
            int jpeg_counter = 0;

            //Check
            while (fread(buffer, sizeof(buffer), 1, input))
            {
                //check 4 first bytes of file to see if they contain the jpg signature
                if ((buffer[0] == 0xff) && (buffer[1] == 0xd8) && (buffer[2] == 0xff) && ((buffer[3] & 0xf0) == 0xe0))
                {
                    if (output != NULL) {
                        // sprintf(char *str, const char *format, ...) and "03i" means 3 digits in format 001, 002...
                        sprintf(files, "i.jpg", jpeg_counter);
                        //use created pointer to save jpeg files from input folder card.raw
                        output = fopen(filename, "w");
                        //add jpeg to the new buffer using ouput pointer
                        fwrite(buffer, sizeof(buffer), 1, output);
                        // update counter
                        jpeg_counter  ;
                    }
                    else //no more files to read(end of folder array) - or no images found.
                    {
                        printf("Could not open file\n");
                        return 0;
                    }
                }
            }

            fclose(output);
            fclose(input);
            return 0;
        }
    }
}

CodePudding user response:

Here is another attempt at a solution, however, it only writes out the first 512 bytes (unlike the original) but I don't think jpeg uses 512 bytes fixed chunks so neither the op or or @BarmakShemirani solution would work as expected. (buffer[3] & 0xf0) == 0xe0 means variable sized, application specific and there is a reference that data is laid out like TIFF, In either case op did not share card.raw so whatever format is used would be speculation:

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

#define FILENAME_LEN 8

int main(int argc, char* argv[]) {
    int r = 0;
    FILE *input = NULL;

    if (argc != 2) {
        printf("./recover Usage: ./recover image \n");
        r = 1;
        goto out;
    }

    char *filename = argv[1];
    input = fopen(filename, "rb");
    if (!strcmp(filename, "card.raw")) {
        printf("Unable to open: %s\n", filename);
        r = 2;
        goto out;
    }

    for(int jpeg_counter = 0; !r; jpeg_counter  ) {
        uint8_t buffer[512];
        size_t n = fread(buffer, sizeof(buffer), 1, input);
        // use an existing library instead?
        if(
            n < 4 ||
            buffer[0] != 0xff ||
            buffer[1] != 0xd8 ||
            buffer[2] != 0xff ||
            (buffer[3] & 0xf0) != 0xe0
        ) {
            printf("invalid header\n");
            r = 3;
            break;
        }

        char filename2[FILENAME_LEN];
        if(snprintf(filename2, FILENAME_LEN, "i.jpg", jpeg_counter) >= FILENAME_LEN) {
            printf("%s: output filename truncated", filename);
            r = 4;
            break;
        };

        FILE *output = fopen(filename2, "wb");
        if(!output) {
            printf("%s: fopen failed\n", filename);
            r = 5;
            break;
        }
        // TBD: replace with a loop once we figure out
        // how a given file is terminated.
        if(fwrite(buffer, n, 1, output) != n) {
            printf("%s: write failed\n", filename);
            r = 6;
        }
        fclose(output);
    }
out:
    if(input) fclose(input);
    return r;
}

CodePudding user response:

uint8_t buffer[512];
fread(buffer, sizeof(buffer), 1, input)

This should be change to: fread(buffer, 1, sizeof(buffer), input). This way fread will read up to 512 bytes. When it gets to the end of file, it reads whatever is left, for example 1 byte, and returns that number. Likewise, fwrite should change. It should write the same number which was read earlier.

Open the file in binary mode.

If fopen fails then stop immediately.

Check the file header only once, not every read loop.

Your condition for checking the file header may have a typo (buffer[3] & 0xf0) == 0xe0. Checking the first 3 bytes should be okay.

int main()
{
    FILE* input = fopen("input.jpg", "rb");
    if (!input)
    { perror("input error"); return 0; }

    FILE* output = fopen("output.jpg", "wb");
    if (!output)
    { perror("output error"); fclose(input); return 0; }

    uint8_t buf[1000];
    int check_header = 1;
    while (1)
    {
        size_t read_count = fread(buf, 1, sizeof(buf), input);
        if (!read_count)
            break;
        if (check_header)
        {
            if (buf[0] == 0xff && buf[1] == 0xd8 && buf[2] == 0xff)
                // && buf[3] == 0xe0 ?
            { printf("header is okay\n"); }
            else
            { printf("not okay\n"); break; }
            check_header = 0; //don't check header again
        }
        fwrite(buf, 1, read_count, output);
    }

    fclose(input);
    fclose(output);
    return 0;
}
  • Related