Hexadecimal find and replace

2019-09-01 06:36发布

问题:

How to change a binary file hexadecimal character in a binary file?

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define BUFFER_SIZE     4096
int main(void)
{
     uint8_t  *buffer;  // Explicit 8 bit unsigned, but should equal "unsigned char"
     FILE     *file;
     char     filename[512] = "test.bin";

     // We could also have used buffer[BUFFER_SIZE], but this shows memory alloc
     if (NULL == (buffer = malloc(BUFFER_SIZE)))
     {
          fprintf(stderr, "out of memory\n");
          return -1;
     }

     // Being inside a { }, crlf won't be visible outside, which is good.
     char     *crlf;
     if (NULL != (crlf = strchr(filename, '\n')))
          *crlf = 0x0;

     if (NULL == (file = fopen(filename, "rb")))
     {
         fprintf(stderr, "File not found: '%s'\n", filename);
         return -1;
     }
     while(!feof(file) && !ferror(file))
     {
          size_t i, n;
          if (0 == (n = (size_t)fread(buffer, sizeof(uint8_t), BUFFER_SIZE, file)))
               if (ferror(file))
                    fprintf(stderr, "Error reading from %s\n", filename);
                    // Here, n = 0, so we don't need to break: next i-cycle won't run
        for (i = 0; i < n; i++)
          {
               printf("%02X ", buffer[i]);
               if (15 == (i % 16))
                   printf("\n"); // Every 16th byte, a newline
         }
     }
     fclose(file); // file = NULL; // This ensures file won't be useable after fclose
     free(buffer); // buffer = NULL; // This ensures buffer won't be useable after free
     printf("\n");
     return 0;
}

reading hex = "00 EB 00 00 50 E3 02" replace hex = "00 EB 01 00 37 E3 02"

回答1:

First, a bit of nomenclature, viz nitpicking: You don't want to change the hexadecimal characters in a file, but the bytes in a byte buffer, which you then print out in hexadecimal format.

If your data were chars, you could use strstr from string.h to find your needle and then overwrite data there with a string of the same length with memcpy. You need a similar function that finds any data which may contain zeros in a byte array. GNU has memmem, but it is non-standard, so let's write one:

/*
 *  Find needle of length len in byte haystack [p, end).
 */
uint8_t *buf_find(uint8_t *p, uint8_t *end, uint8_t *needle, int len)
{
    end = end - len + 1;

    while (p < end) {
        if (memcmp(p, needle, len) == 0) return p;
        p++;
    }
    return NULL;
}

You can the

uint8_t what[] = {0x00, 0xEB, 0x00, 0x00, 0x50, 0xE3, 0x02};
uint8_t repl[] = {0x00, 0xEB, 0x01, 0x00, 0x37, 0xE3, 0x02};

char *p = buffer;
char *end = buffer + n;

for (;;) {
    uint8_t *q = buf_find(p, end, what, sizeof(what));

    if (q == NULL) break;
    memcpy(q, repl, sizeof(repl));
    p = q + sizeof(text);
}

This will not catch needles that sit at the boundaries of the 4096-byte chunks you read in, of course. You can catch these by reading the whole file in a monolithic chunk or by some clever chunk management that allows you to scan the last seven bytes of the previous chunk.



标签: c replace find hex