Как разобрать шестнадцатеричный дамп

У меня есть файл дампа флэш-памяти, который выдает адреса и данные. Я хочу проанализировать данные, чтобы они сказали мне действительные теги. Столбец «002F0900» — это начальные адреса. Пример допустимого тега: «DC 08 00 06 00 00 07 26 01 25 05 09», где «DC 08» = номер тега, «00 06» = длина данных тега, «00 00» = версия тега. Данные тега начинаются после версии, и в этом случае это будет «07 26 01 25 05 09», а следующий тег будет начинаться с «DC 33».

Я могу распечатать первый тег до длины данных, но я не уверен, как распечатать данные, потому что я должен учитывать, перейдут ли данные на следующую строку, поэтому мне придется как-то пропустить адрес . Каждая строка содержит 58 столбцов. Каждый адрес состоит из 8 символов плюс двоеточие и 2 пробела до начала следующего шестнадцатеричного значения.

Мне также в конечном итоге придется подумать, когда в столбце адреса появится «DC». Если бы кто-нибудь мог дать совет, потому что я знаю, как я это делаю, это не лучший способ сделать это. Я просто пытаюсь заставить его работать в первую очередь.

Текстовый файл состоит из тысяч строк, которые выглядят так:

002F0900:  09 FF DC 08 00 06 00 00 07 26 01 25 05 09 DC 33
002F0910:  00 07 00 00 1F A0 26 01 25 05 09 FF 9C 3E 00 08
002F0920:  00 01 07 DD 0A 0D 00 29 35 AD 9C 41 00 0A 00 01
002F0930:  07 DD 0A 0D 00 29 36 1C 1D 01 9C 40 00 02 00 01
002F0940:  01 00 9C 42 00 0A 00 01 07 DD 0A 0D 00 29 36 21
002F0950:  1D AD 9C 15 00 20 00 00 01 00 00 00 00 04 AD AE
002F0960:  C8 0B C0 8A 5B 52 01 00 00 00 00 00 FF 84 36 BA
002F0970:  4E 92 E4 16 28 86 75 C0 DC 10 00 05 00 00 00 00
002F0980:  00 00 01 FF DC 30 00 04 00 01 00 00 00 01 9C 41

Пример вывода:

Tag Number: DC 08
Address: 002E0000    
Data Length: 06
Tag Data: 07 26 01 25 05 09

Исходный код:

#include<stdio.h>
FILE *fp;

main()
{
    int i=0;
    char ch;
    char address[1024];
    char tag_number[5];
    char tag_length[4];
    int number_of_addresses = 0;
    long int length;

    fp = fopen(FILE_NAME,"rb");
    if(fp == NULL) {
        printf("error opening file");
    }
    else {
        printf("File opened\n");
        while(1){
            if((address[i]=fgetc(fp)) ==':')
                break;

            number_of_addresses++;
            i++;
        }

        printf("\nAddress:");
        for (i = 0; i < number_of_addresses;i++)
            printf("%c",address[i]);

        while((ch = fgetc(fp)) != 'D'){ //Search for valid tag
        }

        tag_number[0] = ch;
        if((ch = fgetc(fp)) == 'C')  //We have a valid TAG
        {
            tag_number[1] = ch;
            tag_number[2] = fgetc(fp);
            tag_number[3] = fgetc(fp);
            tag_number[4] = fgetc(fp);
        }

        printf("\nNumber:");
        for(i=0;i<5;i++)
            printf("%c",tag_number[i]);

        fgetc(fp);      //For space
        tag_length[0] = fgetc(fp);
        tag_length[1] = fgetc(fp);
        fgetc(fp);      //For space
        tag_length[2] = fgetc(fp);
        tag_length[3] = fgetc(fp);

        printf("\nLength:");

        for(i=0;i<4;i++)
            printf("%c",tag_length[i]);

        length = strtol(tag_length,&tag_length[4], 16);
        printf("\nThe decimal equilvant is: %ld",length);
        for (i = 0;i<165;i++)
            printf("\n%d:%c",i,fgetc(fp));
    }

    fclose(fp);
}

Обновление @ooga: теги написаны произвольно. Если мы также рассмотрим неверный тег в логике, тогда я смогу выяснить остальное, если потрачу некоторое время. Спасибо


person user2946437    schedule 18.06.2014    source источник
comment
подумайте о том, чтобы сузить этот вопрос, он кажется слишком широким   -  person Marco A.    schedule 18.06.2014
comment
Если все, что у вас есть, это шестнадцатеричный дамп текстового файла, то почему бы сначала не написать программу для преобразования его обратно в двоичную форму, с которой вам будет проще иметь дело. Кстати, почему вы открываете текстовый файл в двоичном режиме?   -  person ooga    schedule 18.06.2014
comment
Ooga: Я не уверен, что преобразование в двоичный формат поможет. Я не знаю, почему... открытие в двоичном формате еще ничего не изменило.   -  person user2946437    schedule 18.06.2014
comment
Преобразование в двоичный формат избавит вас от адресов и разрывов строк. Это также сделало бы чтение значений более простым. У вас есть исходный бинарный файл?   -  person ooga    schedule 18.06.2014
comment
Также просто бессмысленно открывать текстовый файл в бинарном режиме. Вот почему он называется текстовым файлом. Открытие текстового файла в двоичном режиме в Windows приводит к тому, что разрывы строк читаются как \r\n вместо простого старого \n. Могут быть и другие аномалии.   -  person ooga    schedule 18.06.2014
comment
Я не уверен, что это двоичный файл, но у меня есть исходный файл без расширения, в котором я избавился от лишних столбцов и сохранил его как .txt. Мне нужно иметь возможность печатать адреса для соответствующих тегов, смогу ли я это сделать, если у меня есть двоичный файл?   -  person user2946437    schedule 18.06.2014
comment
Поскольку мы не уверены, мы просто будем работать с текстовым файлом. Я вернусь к вам....   -  person ooga    schedule 18.06.2014


Ответы (1)


Это просто идея для начала, так как я не совсем уверен, что вам нужно. Основная идея заключается в том, что read_byte возвращает следующее двузначное шестнадцатеричное значение в виде байта, а также возвращает его адрес.

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

#define FILE_NAME "UA201_dump.txt"

void err(char *msg) {
  fprintf(stderr, "Error: %s\n", msg);
  exit(EXIT_FAILURE);
}

// read_byte
// Reads a single two-digit "byte" from the hex dump, also
// reads the address (if necessary).
// Returns the byte and current address through pointers.
// Returns 1 if it was able to read a byte, 0 otherwise.

int read_byte(FILE *fp, unsigned *byte, unsigned *addr_ret) {

  // Save current column and address between calls.
  static int column = 0;
  static unsigned addr;

  // If it's the beginning of a line...
  if (column == 0)
    // ... read the address.
    if (fscanf(fp, "%x:", &addr) != 1)
      // Return 0 if no address could be read.
      return 0;

  // Read the next two-digit hex value into *byte.
  if (fscanf(fp, "%x", byte) != 1)
    // Return 0 if no byte could be read.
    return 0;

  // Set return address to current address.
  *addr_ret = addr;
  // Increment current address for next time.
  ++addr;

  // Increment column, wrapping back to 0 when it reaches 16.
  column = (column + 1) % 16;

  // Return 1 on success.
  return 1;
}


int main() {
  unsigned byte, addr, afterdc, length, version, i;

  FILE *fp = fopen(FILE_NAME,"r");
  if (!fp) {
    fprintf(stderr, "Can't open %s\n", FILE_NAME);
    exit(EXIT_FAILURE);
  }

  while (read_byte(fp, &byte, &addr)) {
    if (byte == 0xDC) {

      // Read additional bytes like this:
      if (!read_byte(fp, &afterdc, &addr)) err("EOF 1");

      if (!read_byte(fp, &length, &addr)) err("EOF 2");
      if (!read_byte(fp, &byte, &addr)) err("EOF 3");
      length = (length << 8) | byte;

      if (!read_byte(fp, &version, &addr)) err("EOF 4");
      if (!read_byte(fp, &byte, &addr)) err("EOF 5");
      version = (version << 8) | byte;

      printf("DC: %02X, %u, %u\n  ", afterdc, length, version);
      for (i = 0; i < length; ++i) {
        if (!read_byte(fp, &byte, &addr)) err("EOF 6");
        printf("%02X ", byte);
      }
      putchar('\n');
    }
  }

  fclose(fp);
  return 0;
}

Некоторое объяснение:

Каждый раз, когда вызывается read_byte, он считывает следующий напечатанный байт (двузначные шестнадцатеричные значения) из шестнадцатеричного дампа. Он возвращает этот байт, а также адрес этого байта.

В каждой строке 16 двузначных шестнадцатеричных значений. Номер столбца (от 0 до 15) сохраняется в статической переменной между вызовами. Столбец увеличивается после чтения каждого байта и сбрасывается до 0 каждый раз, когда столбец достигает 16.

Каждый раз, когда номер столбца равен 0, он считывает напечатанный адрес, сохраняя его между вызовами в статической переменной. Он также увеличивает статическую переменную addr, чтобы она могла сообщить вам адрес байта в любом месте строки (когда номер столбца не равен нулю).

В качестве примера вы можете использовать read_bye вот так, который печатает значение каждого байта и его адрес в отдельной строке:

// after opening file as fp
while (read_byte(fp, &byte, &addr))
    printf("%08X- %02X\n", addr, byte);

(Не то чтобы это было полезно сделать, но для проверки вы можете запустить его с фрагментом, который вы указали в своем вопросе.)

person ooga    schedule 18.06.2014
comment
Спасибо, я немного запутался, что вы подразумеваете под последовательными байтами и их адресами. Например, что делает первый read_byte(fp, &afterdc, &addr)? - person user2946437; 18.06.2014
comment
Ога: Вау! Я постараюсь настроить его на то, что мне нужно, чтобы показать. Как он узнает/хранит адреса (002F0900)/как вы читаете только 16 столбцов для шестнадцатеричных значений? - person user2946437; 18.06.2014
comment
@user2946437 user2946437 Это, наверное, слишком много, чтобы объяснять здесь! Похоже, вам нужна книга по C. Большая часть магии исходит от fscanf, который (используя спецификацию формата %x) считывает шестнадцатеричное значение из текстового файла. static означает, что значение переменной будет запоминаться между вызовами функции. Также обратите внимание, что read_byte возвращает 0, если обнаруживает конец файла (или какую-то другую проблему), и возвращает 1 в противном случае. Я добавлю несколько комментариев к функции. - person ooga; 18.06.2014
comment
Я вижу это сейчас .... Есть ли способ сказать, чтобы он читал байты длины после версии. Прямо сейчас, если в данных есть байт DC. read_byte считывает DC и запускает новый тег, даже если другой DC является частью данных. - person user2946437; 18.06.2014
comment
@ user2946437 read_byte просто возвращает последовательные байты, не заботясь о значении. Остальная логика зависит от вас. Я могу помочь вам только в том случае, если вы сможете лучше описать (путем редактирования своего вопроса) именно то, что вы пытаетесь сделать (я не совсем понимаю). main выше читает байты, пока не найдет 0xDC, затем читает следующий байт (сохраняя его как afterdc), затем читает следующие два байта (сохраняя их как length), затем читает следующие два байта (сохраняя их как version) и затем он считывает length дополнительных байтов (независимо от того, являются ли они 0xDC или нет). Затем он снова начинает искать 0xDC. - person ooga; 18.06.2014
comment
Позвольте мне сначала понять, что на самом деле происходит, и попробовать логику того, что я хочу (мы очень близки), и я свяжусь с вами. Спасибо - person user2946437; 19.06.2014