0

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"

Lundin
  • 195,001
  • 40
  • 254
  • 396
Mehmet_
  • 5
  • 4
  • Your problem to replace a hex string with another is the same as replacing one text string with another. The only difference is using binary patterns instead of text patterns. To solve the problem, first solve the problem of replacing one text string with another. This will usally involve strstr, memmove and strcpy. To switch to binary strings, simply use memmem instead of strstr and memcpy instead of strcpy. See also http://stackoverflow.com/questions/1992253/a-pure-bytes-version-of-strstr – Brandin Jan 17 '14 at 09:52
  • test.bin 8D E2 21 0E 8D E2 E6 39 00 EB 21 0E 8D E2 A0 39 00 EB 00 30 A0 E1 78 00 9F E5 01 2C A0 E3 05 10 A0 E1 73 39 00 EB 00 00 50 E3 02 00 00 1A 00 00 E0 E3 27 DE 8D E2 70 80 BD E8 14 50 94 E2 45 6F 84 E2 0F 00 00 0A 21 0E 8D E2 C2 39 00 EB 14 20 A0 E3 04 10 A0 E1 21 0E 8D E2 D1 39 00 EB 21 0E 8D E2 8B 39 00 EB 00 30 – Mehmet_ Jan 17 '14 at 09:57
  • Thanks Brandin. will you use directly hex value from the binary file ? – Mehmet_ Jan 17 '14 at 10:01
  • not sure what you mean. What I mean is first write a program that deals with just text strings, say replace "foo" with "bar". Once you have such a program, and provided your implementation uses strstr and strcpy, then upgrading this program to work with an arbitrary binary string such as "\000\000\000" instead of "foo" will basically just mean using memmem and memcpy – Brandin Jan 17 '14 at 10:08

1 Answers1

0

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.

M Oehm
  • 28,726
  • 3
  • 31
  • 42
  • thanks M Oehm,working code in 4kb file. but my file 32mb the resulting file 0kb – Mehmet_ Jan 17 '14 at 13:09
  • @Mehmet_: That probably has to do with the way you write the byte array to a file. That part of the code is not in your example above, so I can't help you there. – M Oehm Jan 17 '14 at 14:35
  • @M Oehm Buffer size error my example its wery slow your code replace my new example but not working – Mehmet_ Jan 17 '14 at 15:00
  • @Mehmet_: I'm sorry, I don't understand what you mean. You'll have to be more specific. (If you have problems writing abuffer to a file, why don't you open a new question?) – M Oehm Jan 17 '14 at 15:15
  • M Oehm it works slower due to buffer size i make new example code but your coding is not properly working. – Mehmet_ Jan 17 '14 at 15:29
  • ok M Oehm new question http://stackoverflow.com/questions/21189683/find-and-replace-hex – Mehmet_ Jan 17 '14 at 15:32
  • @Mehmet_: "Not working" is not a good explanation of an error. What do you expect? What does it do? And of course, my implementation was not optimised for speed, but it should get the job done in reasonable time. – M Oehm Jan 17 '14 at 17:16
  • You are asking the same question again over there. That's not what I had in mind. I thought you had problems writing the file. Also, your solution is slow, because you read the file byte by byte, _unlike_ the way you read the file here. Please learn to be consistent. – M Oehm Jan 17 '14 at 17:26