Hexdump und magic string

lano

Aktives Mitglied
Moin.
Ich hab da nen kleines Problem.

Ich möchte Dateien anhand ihrer ersten 40 byte erkennen.
Dazu hab ich mir Folgendes gedacht...
Drei Programme...

Das erste "fb_hexdump" liest die ersten 40 byte einer datei und gibt sie als hex aus.
Bash:
fb_hexdump -f fb_hexdump
7F454C46010101000000000000000000020028000100000038050100340000003C1D000000040005

Das zweite "fb_hexdump_compare" liest die liste der hex dumps ein und erstelle einen hex string in dem die bits makiert sind die bei allen hex dumps gleich sind.
Das geht bei mir schief.
Das ist zB meine Liste die verglichen werden soll.
Bash:
find . -type f -name "*.sh" -exec fb_hexdump  -f {} \; | grep ^23
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323
23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20636667
23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461
23212F62696E2F73680A0A232052657065617465720A6966205B202D78202F7362696E2F72657874
23212F62696E2F73680A0A6966205B202D65202F7661722F746D702F7765626461762E6C6F67205D
23212F62696E2F73680A0A666F72206620696E2024286C73202F7661722F746D702F6C69626D7372
23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20426F78
23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20736367
23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461
23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461
23212F62696E2F73680A0A23203D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0A2320636F6D6D6F6E
23212F62696E2F73680A0A230A2320536574757020616E64206272696E6775702074686520504D49
23212F62696E2F73680A0A230A2320536574757020746865205652583631382044534C2D6461656D
23212F62696E2F73680A232323203D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0A23232320546869
23212F62696E2F73680A0A230A2320636F6E6669677572652074686520434F2F435045206C696E65
23212F62696E2F73680A0A230A232053657475702074686520565258363138206461746170617468
23212F62696E2F73680A0A230A2320536574757020616E64206272696E6775702074686520565258
23212F62696E2F73680A0A23232054686973207363726970742063616E20626520757365642C2074
2323237374204350452073746172747570207363726970742323232323232323230A232323232323
2321202F62696E2F73680A6578656320323E202F6465762F636F6E736F6C650A2323204C6F616469
2321202F62696E2F73680A49474E4F52455F414E445F45584954202829207B0A6563686F2049474E
23212F62696E2F73680A0A0A232055506E50207265717569726573206C6F6F706261636B0A696663
23212F62696E2F73680A0A5245424F4F545F464F525F5550444154453D60636174202F70726F632F
23212F62696E2F73680A232323232323232323232323232323232323232323232323230A23232323
2321202F62696E2F73680A0A44454255474F5054533D22220A6966205B2022247B3123232D646562
23212F62696E2F73680A2323204B756E64656E2D4669726D776172650A2323204C6F6767696E6720
23212F62696E2F73680A746666735F6E6F6465735F696E69742829207B0A23232323232323232323
2321202F62696E2F73680A6361736520243120696E0A7374617274290A7069646F66207069637475
2321202F62696E2F73680A0A6361736520243120696E0A0A7374617274290A202020206966205B20
23212F62696E2F73680A232323232323232323232323232323232323232323232323232323232323
23212F62696E2F73680A2320496E636C756465206D6F64656C20696E666F726D6174696F6E0A0A47
2321202F62696E2F73680A2323232323232323232323232323232323232323232323232323232323
23212F62696E2F73680A2320696E74656E74696F6E616C6C79206C65667420626C616E6B0A656368
23212F62696E2F73680A233D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D
2321202F62696E2F73680A4D41585F444F574E4C4F41445F53495A453D313030300A696E3D222431
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323
2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323
23212F62696E2F73680A0A74726170202222205349474855500A0A56455253494F4E3D27312E3020
23212F62696E2F73680A2320696E74656E74696F6E616C6C79206C65667420626C616E6B0A656368
23212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323

Wenn ich das durch Programm Nummer 2 schiebe erhalte ich sowas:
Bash:
find . -type f -name "*.sh" -exec fb_hexdump  -f {} \; | grep ^23 | fb_hexdump_compare
Original Hex Dump:
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
Compare Hex Dump:

Original Hex Dump:
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
Compare Hex Dump:
2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323
Original Hex Dump:
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
Compare Hex Dump:

Original Hex Dump:
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
Compare Hex Dump:
23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20636667
Original Hex Dump:
2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D
Compare Hex Dump:

Hex Representation of Differences:
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Die Ausgabe ist nicht richtig...


Das dritte "fb_magic" soll einen übergebenen hexdump mit einer liste von bekannten vergleichen und den datei typ ausgeben.
Bash:
fb_magic 2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D

ich hab mir gedacht ich speichere die daten in fb_magic so
C:
{"Shell File", "23212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323",
 "00020F5D1F4F6D7F3F6A7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F"},

Lasst euch von den unterschiedlichen Werten nicht verwirren, es dient nur als beispiel.

Meine Frage an sich.... Kann man das so machen? Gibts da nen einfacheren Weg?
 
Also ich nehme mal an, bei fb_hexdump_compare legst du die Werte als Maske alle übereinander oder AND-verknüpfst die Stellen mit ihren jeweiligen Gegenparts. Dann reicht schon ein einziger Abweichler, um die Endmaske komplett auszunullen oder zu F'en.

Wenn du sie wie gezeigt schon vorab filterst (mit absoluten Positionen), sollte es aber trotzdem zumindest ein paar Übereinstimmungen geben. Vielleicht hat sich da ein Fehler bei fb_hexdump_compare eingeschlichen. Kannst ja den relevanten Abschnitt mal posten.

Meine Frage an sich.... Kann man das so machen? Gibts da nen einfacheren Weg?
Da spricht erstmal nichts gegen. Die Vorgehensweise mit den Masken lässt sich sowohl in Echtzeit als auch auf vorab gefilterte Listen anwenden.

Ich hätte das aber wahrscheinlich erstmal mit eingebauter Dateierkennung ausprobiert. Zum Beispiel mit file. Selbst wenn du da genauere Unterscheidungen brauchst, kannst du das trotzdem mit file vorfiltern.

Bin schon wieder ein bisschen raus aus dem Thema, aber man kann auch eine Art Sieb für die Datentypen anlegen (mittels MSD, Tries oder irgendwelchen anderen Stringsortierverfahren) und das dann zum Einsortieren der Dateihashes nutzen, für den JSON-Output. Ist aber zu viel des Guten, denke ich.
 
Erst mal ... C? Denn in dem Forum hast du gepostet.

anhand ihrer ersten 40 byte
Nee. Anhand der Magic Number. Die ist (wenn vorhanden) für unterschiedliche Dateitypen unterschiedlich lang. Wenn du einfach versuchst die Magic Number von mehreren Dateien gleichem Typs durch Ausschluss der Bits und Bytes zu ermitteln, die unterschiedlich sind, hast du wahrscheinlich immer noch zufällig gleiche Bytes innerhalb der ersten 40 die nix mit der Magic Number zu tun haben.
 
Also ich nehme mal an, bei fb_hexdump_compare legst du die Werte als Maske alle übereinander oder AND-verknüpfst die Stellen mit ihren jeweiligen Gegenparts. Dann reicht schon ein einziger Abweichler, um die Endmaske komplett auszunullen oder zu F'en.

Hmm..
Kann wohl passieren. Würde ich jetzt erst mal ignorieren wollen.
Nehmen wir an ich hab:
1100101 und
1100010
so ist das Ergebnis:
1111000
Ersten 4bit müssen gleich sein. letzten drei bit werden ignoriert.

Bisher scheint das eigentlich ganz gut zu funktionieren. Mit Einschränkungen.
Ich hätte das aber wahrscheinlich erstmal mit eingebauter Dateierkennung ausprobiert. Zum Beispiel mit file. Selbst wenn du da genauere Unterscheidungen brauchst, kannst du das trotzdem mit file vorfiltern.
Ich filtere quasi am mime typ vor.
file erkennt aber in der regel nur Data und das wars.

Bin schon wieder ein bisschen raus aus dem Thema, aber man kann auch eine Art Sieb für die Datentypen anlegen (mittels MSD, Tries oder irgendwelchen anderen Stringsortierverfahren) und das dann zum Einsortieren der Dateihashes nutzen, für den JSON-Output. Ist aber zu viel des Guten, denke ich.
Das scheint mir ein bisschen oversized.

Erst mal ... C? Denn in dem Forum hast du gepostet.
Ja... Mich hats auch gewundert. Aber ist kein malloc drin :)
Wenn du einfach versuchst die Magic Number von mehreren Dateien gleichem Typs durch Ausschluss der Bits und Bytes zu ermitteln, die unterschiedlich sind, hast du wahrscheinlich immer noch zufällig gleiche Bytes innerhalb der ersten 40 die nix mit der Magic Number zu tun haben.
Eigentlich geht es ja darum.
Es haben halt nicht alle Dateien eine Magic Number. Darum hab ich gedacht ich teste quasi das Dateiformat.

Es geht im Grunde um ne ganze reihe AVM eigener Formate.
Ich hab ~5000 Firmware Images und entpacke die. Dabei sollen über die Dateien so viele Informationen gesucht/gefunden werden wie möglich.
 
Ich kann dir das nicht in der Bash vorturnen, nur in C. Aber ich denke nicht dass ein Bitweiser Vergleich das ist was du suchst.
C:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define HEX_DIGITS_PER_BYTE 2
#define DIGITS_PER_CHUNK (40 * HEX_DIGITS_PER_BYTE)
#define NGRAM_DIGITS                                                                                                                                                               \
  (sizeof(unsigned long) * HEX_DIGITS_PER_BYTE) // 40 Bytes ist ein Vielfaches der Breite eines `unsigned long`, heißt wir können mehrere Bytes zusammen verarbeiten

static char *filter(char *pattern, const char *chunk) {
  char nGramPat[NGRAM_DIGITS + 1] = {0}, nGramChnk[NGRAM_DIGITS + 1] = {0};
  for (int i = 0; i < DIGITS_PER_CHUNK; i += NGRAM_DIGITS) {
    sprintf(nGramPat, "%0*X", NGRAM_DIGITS,
            (strtoul(memcpy(nGramPat, pattern + i, NGRAM_DIGITS), NULL, 16) & strtoul(memcpy(nGramChnk, chunk + i, NGRAM_DIGITS), NULL, 16))); // Binary AND

    memcpy(pattern + i, nGramPat, NGRAM_DIGITS);
  }

  return pattern;
}

static bool match(const char *pattern, const char *chunk) {
  char nGramPat[NGRAM_DIGITS + 1] = {0}, nGramChnk[NGRAM_DIGITS + 1] = {0};
  for (int i = 0; i < DIGITS_PER_CHUNK; i += NGRAM_DIGITS) {
    const unsigned long vPat = strtoul(memcpy(nGramPat, pattern + i, NGRAM_DIGITS), NULL, 16);
    if ((vPat & strtoul(memcpy(nGramChnk, chunk + i, NGRAM_DIGITS), NULL, 16)) != vPat)
      return false;
  }

  return true;
}

int main(void) {
  char pattern[] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";

  static const char chunks[][DIGITS_PER_CHUNK + 1] = {
      "2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D", "2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323",
      "23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20636667", "23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461",
      "23212F62696E2F73680A0A232052657065617465720A6966205B202D78202F7362696E2F72657874", "23212F62696E2F73680A0A6966205B202D65202F7661722F746D702F7765626461762E6C6F67205D",
      "23212F62696E2F73680A0A666F72206620696E2024286C73202F7661722F746D702F6C69626D7372", "23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20426F78",
      "23212F62696E2F73680A0A6563686F2022232323232320424547494E2053454354494F4E20736367", "23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461",
      "23212F62696E2F73680A736574202D65756F20706970656661696C0A0A2320537570706F72746461", "23212F62696E2F73680A0A23203D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0A2320636F6D6D6F6E",
      "23212F62696E2F73680A0A230A2320536574757020616E64206272696E6775702074686520504D49", "23212F62696E2F73680A0A230A2320536574757020746865205652583631382044534C2D6461656D",
      "23212F62696E2F73680A232323203D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0A23232320546869", "23212F62696E2F73680A0A230A2320636F6E6669677572652074686520434F2F435045206C696E65",
      "23212F62696E2F73680A0A230A232053657475702074686520565258363138206461746170617468", "23212F62696E2F73680A0A230A2320536574757020616E64206272696E6775702074686520565258",
      "23212F62696E2F73680A0A23232054686973207363726970742063616E20626520757365642C2074", "2323237374204350452073746172747570207363726970742323232323232323230A232323232323",
      "2321202F62696E2F73680A6578656320323E202F6465762F636F6E736F6C650A2323204C6F616469", "2321202F62696E2F73680A49474E4F52455F414E445F45584954202829207B0A6563686F2049474E",
      "23212F62696E2F73680A0A0A232055506E50207265717569726573206C6F6F706261636B0A696663", "23212F62696E2F73680A0A5245424F4F545F464F525F5550444154453D60636174202F70726F632F",
      "23212F62696E2F73680A232323232323232323232323232323232323232323232323230A23232323", "2321202F62696E2F73680A0A44454255474F5054533D22220A6966205B2022247B3123232D646562",
      "23212F62696E2F73680A2323204B756E64656E2D4669726D776172650A2323204C6F6767696E6720", "23212F62696E2F73680A746666735F6E6F6465735F696E69742829207B0A23232323232323232323",
      "2321202F62696E2F73680A6361736520243120696E0A7374617274290A7069646F66207069637475", "2321202F62696E2F73680A0A6361736520243120696E0A0A7374617274290A202020206966205B20",
      "23212F62696E2F73680A232323232323232323232323232323232323232323232323232323232323", "23212F62696E2F73680A2320496E636C756465206D6F64656C20696E666F726D6174696F6E0A0A47",
      "2321202F62696E2F73680A2323232323232323232323232323232323232323232323232323232323", "23212F62696E2F73680A2320696E74656E74696F6E616C6C79206C65667420626C616E6B0A656368",
      "23212F62696E2F73680A233D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D", "2321202F62696E2F73680A4D41585F444F574E4C4F41445F53495A453D313030300A696E3D222431",
      "2321202F62696E2F73680A0A4C4F43414C5F444F574E4C4F41445F4E414D453D222F7661722F746D", "2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323",
      "2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323", "23212F62696E2F73680A0A74726170202222205349474855500A0A56455253494F4E3D27312E3020",
      "23212F62696E2F73680A2320696E74656E74696F6E616C6C79206C65667420626C616E6B0A656368", "23212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323"};

  for (int i = 0; i < 42; ++i)
    filter(pattern, chunks[i]);

  printf("Vergleichspattern:\n%s\n\n", pattern);

  static const char chunk1[] = "23212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323";

  static const char chunk2[] = "33212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323";

  static const char chunk3[] = "43212F62696E2F73680A0A2323232323232323232323232323232323232323232323232323232323";

  // erstes Pattern Byte 00100011

  // erstes Chunk Byte   00100011
  //                       ^   ^^
  puts(match(pattern, chunk1) ? "Match" : "No Match");
  // erstes Chunk Byte   00110011
  //                       ^   ^^
  puts(match(pattern, chunk2) ? "Match" : "No Match");
  // erstes Chunk Byte   01000011
  //                       ^   ^^
  puts(match(pattern, chunk3) ? "Match" : "No Match");
  return 0;
}

Ausgabe:
Code:
Vergleichspattern:
23212022602002004000000000000000000000000000000000000000000000000000000000000000

Match
Match
No Match
Alle Bits von chunk2 sind auch im Vergleichspattern. Somit gibt's ein Match...
 
Ich kann dir das nicht in der Bash vorturnen, nur in C
In Bash sollte das auch nicht sein.
Du kannst mir wahrscheinlich helfen die erkannten Dateien zu parsen, bzw da infos raus zu ziehen.
Aber dazu später mehr.


Erstmal hab ich jetzt mein Programm fb_hexdump. Das scheint so auch ganz sinnig zu funktionieren. Zumindest komm ich damit ganz gut klar.

C:
#include "version.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void printHelp() {
  printf("FRITZ!Box command line tools - fb_hexdump %s\n\n", VERSION);
  printf("Usage: fb_hexdump [-b|--bit] -f|--file <Dateiname>\n");
  printf("Optionen:\n");
  printf("  -b, --bit     Ausgabe in Bits statt Hex\n");
  printf("  -f, --file    Dateipfad angeben\n");
  printf("  -s, --size    Anzahl bytes\n");
  printf("  -h, --help    Hilfe anzeigen\n");
  printf("\n");
}

size_t getFileSize(const char *filename) {
  FILE *file = fopen(filename, "rb");
  if (file == NULL) {
    perror("Fehler beim Öffnen der Datei");
    exit(EXIT_FAILURE);
  }
  fseek(file, 0, SEEK_END);
  size_t size = ftell(file);
  fclose(file);
  return size;
}

void printFileExtension(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (dot && dot != filename) {
    printf("%s", dot + 1);
  }
}

void printBytes(const char *filename, int useBits, int useExtension, int useNames, size_t useSize) {
  FILE *file = fopen(filename, "rb");

  if (file == NULL) {
    perror("Fehler beim Öffnen der Datei");
    exit(EXIT_FAILURE);
  }

  unsigned char buffer[useSize];
  size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);

  if (bytesRead > 0) {
    if (useBits) {
      for (size_t i = 0; i < bytesRead; i++) {
        for (int j = 7; j >= 0; j--) {
          printf("%d", (buffer[i] >> j) & 1);
        }
      }
      printf("\n");
    } else {
      for (size_t i = 0; i < bytesRead; i++) {
        printf("%02X", buffer[i]);
      }
      if (useNames) {
        printf("\t%s", filename);
      }
      if (useExtension) {
        printf("\t");
        printFileExtension(filename);
      }
      printf("\n");
    }
  } else {
    printf("Fehler beim Lesen der Datei.\n");
  }
  fclose(file);
}

int main(int argc, char *argv[]) {
  int useBits = 0;
  int useExtensions = 0;
  int useNames = 0;
  const char *filename = NULL;
  size_t useSize = 40;

  for (int i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bit") == 0) {
      useBits = 1;
    } else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--extensions") == 0) {
      useExtensions = 1;
    } else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--names") == 0) {
      useNames = 1;
    } else if ((strcmp(argv[i], "-f") == 0 || strcmp(argv[i], "--file") == 0) && i + 1 < argc) {
      filename = argv[i + 1];
      i++;
    } else if ((strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--size") == 0) && i + 1 < argc) {
      useSize = (long)atoi(argv[i + 1]);
      i++;
    } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
      printHelp();
      return EXIT_SUCCESS;
    } else {
      printHelp();
      printf("Unbekannte Option: %s\n", argv[i]);
      return EXIT_FAILURE;
    }
  }

  if (filename == NULL) {
    printHelp();
    printf("Dateiname fehlt.\n");
    return EXIT_FAILURE;
  }

  if (getFileSize(filename) >= useSize) {
    printBytes(filename, useBits, useExtensions, useNames, useSize);
  } else {
    for (size_t i = 1; i <= useSize; i++) {
      printf("00");
    }
    printf("\n");
  }

  return EXIT_SUCCESS;
}

Man kann das sicher noch besser machen. Es funktioniert jedoch soweit.
Ich kann jetzt mit find . -name "*.html" -exec fb_hexdump -f {} \; ne Liste an hexdumps bekommen.
Code:
3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E
3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E
3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E
3C21444F43545950452068746D6C3E0D0A3C68746D6C3E0D0A093C686561643E0D0A09093C746974
3C21444F43545950452068746D6C3E0D0A3C68746D6C3E0D0A093C686561643E0D0A09093C746974
3C21444F43545950452068746D6C3E0D0A3C68746D6C3E0D0A093C686561643E0D0A09093C746974
...

Ich hab mir gedacht 40byte sollten erst mal reichen, hab dann aber noch nen bisschen Flexibilität eingebaut damit man die Anzahl bytes angeben kann.

Jetzt will ich die Liste an hexdumps vergleichen, wie ja schon beschrieben....
 
Zum Vergleichen hab ich mir das hier gebastelt:
C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void hexToBinary(const char *hex, char *binary) {
  while (*hex) {
    switch (*hex) {
    case '0':
      strcat(binary, "0000");
      break;
    case '1':
      strcat(binary, "0001");
      break;
    case '2':
      strcat(binary, "0010");
      break;
    case '3':
      strcat(binary, "0011");
      break;
    case '4':
      strcat(binary, "0100");
      break;
    case '5':
      strcat(binary, "0101");
      break;
    case '6':
      strcat(binary, "0110");
      break;
    case '7':
      strcat(binary, "0111");
      break;
    case '8':
      strcat(binary, "1000");
      break;
    case '9':
      strcat(binary, "1001");
      break;
    case 'a':
    case 'A':
      strcat(binary, "1010");
      break;
    case 'b':
    case 'B':
      strcat(binary, "1011");
      break;
    case 'c':
    case 'C':
      strcat(binary, "1100");
      break;
    case 'd':
    case 'D':
      strcat(binary, "1101");
      break;
    case 'e':
    case 'E':
      strcat(binary, "1110");
      break;
    case 'f':
    case 'F':
      strcat(binary, "1111");
      break;
    default:
      break;
    }
    hex++;
  }
}

void compareHexDumps(const char *baseDump, const char *compareDump, int *differences) {
  char binaryBase[1000] = "", binaryCompare[1000] = "";
  hexToBinary(baseDump, binaryBase);
  hexToBinary(compareDump, binaryCompare);

  int len = strlen(binaryBase);
  for (int i = 0; i < len; i++) {
    if (binaryBase[i] != binaryCompare[i]) {
      differences[i] = 0;
    }
  }
}

void printHexFromBinary(int *differences, int length) {
  printf("\"");
  for (int i = 0; i < length; i += 4) {
    int decimalValue = 8 * differences[i] + 4 * differences[i + 1] + 2 * differences[i + 2] + differences[i + 3];
    printf("%X", decimalValue);
  }
  printf("\", ");
}

int main() {

  char baseHexDump[82], compareHexDump[82];
  int differences[320]; // Anzahl der Bits im Hexdump

  for (int i = 0; i < 320; i++) {
    differences[i] = 1;
  }

  if (fgets(baseHexDump, sizeof(baseHexDump), stdin) == NULL) {
    fprintf(stderr, "Error reading input.\n");
    return 1;
  }

  baseHexDump[80] = '\0';
  printf("Original Hex Dump: %s\n", baseHexDump);
  printf("\n");

  while (fgets(compareHexDump, sizeof(compareHexDump), stdin) != NULL) {
    compareHexDump[strcspn(compareHexDump, "\n")] = '\0';
    compareHexDumps(baseHexDump, compareHexDump, differences);
  }
  printf("    { \"%s\", ", baseHexDump);
  printHexFromBinary(differences, 320);
  printf(" \"-File\" },\n");

  return 0;
}

Ich lese die Liste an hexdumps von stdin. Der erste wird meine Basis und die nachfolgenden vergleiche ich einfach immer mit dem ersten.
Das rechnet jetzt damit das die hexdumps immer 40byte sind. Bin froh das das überhaupt funktioniert....

Nu kann ich das so machen: find . -name "*.html" -exec fb_hexdump -f {} \; | fb_hexdump2magic
Und bekomme als Ausgabe:
Code:
Original Hex Dump: 3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E

    { "3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E", "00000080808080808080808080808080808080808080808080808080808080808080808080808080",  "-File" },

Das reicht mir eigentlich schon hin. Ich bin noch am überlegen wie ich die länge des hexdumps da unter bekomme. In 98% der Fälle reichen mir 40 byte lang hin. Es gibt allerdings Dateien die erst mal 100+byte nullen haben, zb manche partitions images. Da dachte ich das ich vllt führende nullen einfach überspringe und erst ab der position die nicht 0 ist 40 bytes dumpe. Aber das artet dann auch alles schnell in viel Arbeit aus.

Das Ergebnis
Code:
    { "3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E", "00000080808080808080808080808080808080808080808080808080808080808080808080808080",  "-File" },
kopiere ich nu in den source von meinem fb_magic....
 
Letzter Teil ist fb_magic..
C:
#include "fb_magic.h"
#include "version.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int hexCharToBin(char hex) {
  switch (hex) {
  case '0':
    return 0b0000;
  case '1':
    return 0b0001;
  case '2':
    return 0b0010;
  case '3':
    return 0b0011;
  case '4':
    return 0b0100;
  case '5':
    return 0b0101;
  case '6':
    return 0b0110;
  case '7':
    return 0b0111;
  case '8':
    return 0b1000;
  case '9':
    return 0b1001;
  case 'A':
  case 'a':
    return 0b1010;
  case 'B':
  case 'b':
    return 0b1011;
  case 'C':
  case 'c':
    return 0b1100;
  case 'D':
  case 'd':
    return 0b1101;
  case 'E':
  case 'e':
    return 0b1110;
  case 'F':
  case 'f':
    return 0b1111;
  default:
    return -1; // Error: invalid hex character
  }
}

void hexStringToBinary(const char *hexString, char *binaryString) {
  size_t length = strlen(hexString);
  for (size_t i = 0; i < length; i++) {
    int binValue = hexCharToBin(hexString[i]);
    if (binValue != -1) {
      // Convert each hex character to 4 bits binary
      binaryString[i * 4] = (binValue & 0b1000) ? '1' : '0';
      binaryString[i * 4 + 1] = (binValue & 0b0100) ? '1' : '0';
      binaryString[i * 4 + 2] = (binValue & 0b0010) ? '1' : '0';
      binaryString[i * 4 + 3] = (binValue & 0b0001) ? '1' : '0';
    } else {
      // Invalid hex character
      binaryString[i * 4] = '0';
      binaryString[i * 4 + 1] = '0';
      binaryString[i * 4 + 2] = '0';
      binaryString[i * 4 + 3] = '0';
    }
  }
  binaryString[length * 4] = '\0';
}

int compareHexDumps(const char *hexdump1, const char *hexdump2, const char *mask) {
  char binaryMask[321];
  char binaryHexdump1[321];
  char binaryHexdump2[321];

  hexStringToBinary(mask, binaryMask);
  hexStringToBinary(hexdump1, binaryHexdump1);
  hexStringToBinary(hexdump2, binaryHexdump2);

  size_t length = strlen(mask);
  for (size_t i = 0; i < length; i++) {
    if (binaryMask[i] == '1' && binaryHexdump1[i] != binaryHexdump2[i]) {
      return 0; // Bits don't match
    }
  }
  return 1; // All marked bits match
}

void compareAndPrint(const HexDumpInfo *files, size_t numFiles, const char *inputHexDump) {
  unsigned int found = 0;
  for (size_t i = 0; i < numFiles; i++) {
    if (compareHexDumps(files[i].hexdump, inputHexDump, files[i].mask)) {
      printf("FB_MAGIC=\"%s\"\n", files[i].filename);
      found = 1;
    } else {
    }
  }
  if (!found) {
    printf("FB_MAGIC=\"Unknown-File\"\n");
  }
}

int main(int argc, char *argv[]) {
  if (argc != 2) {
    printf("FRITZ!Box command line tools - fb_magic %s\n", VERSION);
    printf("Usage: %s <input_hexdump>\n", argv[0]);
    return 1;
  }

  size_t numFiles = sizeof(files) / sizeof(files[0]);
  printf("fb_magic=%s\n", VERSION);
  compareAndPrint(files, numFiles, argv[1]);

  return 0;
}

Ich hab schon ein bisschen rum getestet.
C:
typedef struct {
  char *hexdump;
  char *mask;
  char *filename;
} HexDumpInfo;

HexDumpInfo files[] = {
    // Need this for Files <40byte && for Test File
    {"00000000000000000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "Unknown-File"},
    {"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "TEST-File"},

    // Add more files as needed

    {"73717368000000000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFD220FE030802FFFEFFFFFFFFFE0AFFFBFFEFFD3FFFFEFFF8FFFFFFFFFFEE0840E00E",
     "Squashfs_BE-File"},
    {"73717368000010990142A463000100000000012F0004001002C00001000400000000000083321BC5", "FFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000",
     "Squashfs_BE-File"},
    {"687371733E0E000000F6DD0000000100BB00000004001000C002010004000000A81F206300000000", "FFFFFFFFFFFFFFFF6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFF",
     "Squashfs_LE-File"},

    {"56455233496E74656C5F556E69666965645F496D61676500007A0704001002080000000303AB63FC", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF0E0FFE0C0C0FFFFFFFFF8000000",
     "UIMG-File"},

    {"009080400098804000601A40FEFF1B2424D05B03BFFF1B3CFFFF7B3724D05B0300609A4000688040", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "Urlader_Image-File"},

    {"1291EDFE2C0A6000000050808112EDFE118832000000508001025A07F98732000378B400DBB854FB", "FFFFFFFF030080FFFFFFFFFFFFFFFFFF0000E0FFFFFFFFFFFFFFFFFF0000E0FF0C0080FF00000000",
     "Kernel_Image-File"},

    {"8112EDFE2C3E32000080208001025A07143E3200CC009D001DA791395D0000800000000000008039", "FFFFFFFF0080C1FFFF5FDFFFFFFFFFFF0080C1FF000000FF81000134FFFFFFFFFFFFFFFFFFFF1038",
     "Kernel_Image-File"},
    {"8112EDFE812D24000000068001025A07692D2400AFF47100938047FE5D0000800000000000006FFD", "FFFFFFFF0000C0FFFF5FC82AFFFFFFFF0000C0FF000000FF00000000FFFFFFFFFFFFFFFFFFEF1038",
     "Kernel_Image-File"},

    {"6D61636120202020202020202020202020202020202020206F76657277726974650A6D6163622020", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "urlader.config-File"},

    {"A92041564D20476D624820323030362E20416C6C652052656368746520766F72626568616C74656E", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "Signature-File"},
    {"7F454C46010201000000000000000000000200080000000100400420000000340000D3CC70001007", "FFFFFFFFFFFCFFFCFFFFFFFFFFFFFFFFFCFCD7D7FEFFFFFE03303003CBFFFFCB0300000388EDED88",
     "Checksum-File"},
    {"4649524D5741524556455253494F4E3D3131332E30372E31392C2D37343934392C37343934392C0A", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF8F0FFFFFFFFF8F0FFFEF0F0F0F0F0E0E0F0F0F0F0E0C0",
     "Version-File"},
    {"C2A92041564D20476D624820323030362E20416C6C652052656368746520766F72626568616C7465", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "Info.txt-File"},
    {"A92041564D20476D624820323030362E20416C6C652052656368746520766F72626568616C74656E", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "Info.txt-File"},

    {"3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D382220737461", "FFB3F1F5B3A0E0A0A0C0A0B0A0A080A0A0A0A0A0E0E0A0A0A0A0A0A0A0808080808080A0A0A08080",
     "SVG-File"},
    {"2321202F62696E2F73680A0A23232323232323232323232323232323232323232323232323232323", "FFFDF0A2E0B09280C095808080808080808080808080808080808080808080808080808080808080",
     "Shell-File"},
    {"89504E470D0A1A0A0000000D4948445200000004000000040806000000A9F19E7E00000019494441", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC00FFFFFC00FFFAFFFFFE00000000FFFFFC00C0E0E0",
     "PNG-File"},
    {"FFD8FFE000104A46494600010200006400640000FFEC00114475636B79000100040000003C0000FF", "FFFFFFFEFFF7F0C1DFDFFFFEB4B6D59BF79BFFFF0013FFEEBB8A9C947913FEEEBF8A9C9482FFFE00",
     "JPG-File"},
    {"3C21444F43545950452068746D6C3E0A3C68746D6C3E0A093C686561643E0A09093C7469746C653E", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C9ABE3E6FEA189808180A2A0A080808080808082A0A0A080",
     "HTML-File"},

    {"12000042010300420703004201030042010300420103004207030042070300420203004207030042", "FFFFFFFF00FCFFFF00FCFFFF00FCFFFF00FCFFFF00FCFFFF00FAFFFF00FAFFFF02FCFFFF00FCFFFF",
     "BIN-File"},
    {"3082010A0282010100C3103570AD35A760A8A529C7112F2BFC143239B3350D642FAECEFB56539FB6", "FFFFFFD7CD70F8F7D5800000100000000602080010200C0000400C00400001800000000000000000",
     "BIN-File"},
    {"EA001DABEAFFFFFEEAFFFFFEEAFFFFFEEAFFFFFEEAFFFFFEEA000000EA000033EA002199EB002183", "FFFFFE5AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC19AFFFFC19A",
     "BIN-File"},

    {"4D3110044000008000EA10F900000000530016C83FFE000080007F003FFE190800000A3D00000CCC", "FFFFFFF9FFFFFFFFFFEE32F0FFFFFFFFFFFFF4E7FFFFFFFFFFFFFFFFFFFFC6E7FFFFFFFFFFFFFFFF",
     "MBIN-File"},

    {"2E2F7661722F00000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "TAR-File"},
    {"2E2F0000000000000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "TAR-File"},

    {"50350A313238203131390A3235350AFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", "FFFFFFFCF9F7D5FCFBF5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
     "PGM-File"},

    {"202F9F4301011234567890120000000015E000020060000075570201000000000200000DFF000000", "FFFF0000FFFFEDC8D6015001FFFFDFFFC03FFFFCFD9FFFFF80A768FEFFFFFFFFE0FFFFC033FFFFFF",
     "Board_Data_BIN-File"},

    {"1B4C7561510000040404040400000013406461656D6F6E5F626173652E6C75615F63000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFE0E1E8E4F5C8C0E8E0E080A0A4E2C1C180908A9EA09CFF",
     "LTE_LUA_LIB-File"},
    {"3C3F6C75610A696620286E696C203D3D20626F782E676C6F622E646F63726F6F7429207468656E0A", "FFFFFFFFFFFFA0808080900000A0A0808080A0A08080A08080808080808080808080808080808080",
     "LUA_Script-File"},
    {"7F454C4601020100000000000000000000030008000000010000053000000034000011C470001007", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFA00003FFFFFFFF",
     "SharedObject-File"},
    {"50726F647563743D467269747A5F426F785F4857323133612028465249545A21426F782036343930", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF0F0BEF791EBE4E2F1848CD0E0A088808080A0",
     "Content-File"},

    {"617237636667207B0A20202020202020206D6F6465203D2064736C646D6F64655F726F757465723B", "FFFFFFFFFFFFFFFFF8808080A0A08080A0808080A080808080808080808080808080808080808080",
     "ar7.cfg-File"},
    {"7472303639636667207B0A2020202020202020656E61626C6564203D207965733B0A202020202020", "FFFFFFFFFFFFFFFFFFFFD0D4BAB0B0B0B0B0B2B2A0A0A0A080A080C0A2A0A0A080808084D5FFFF9B",
     "tr069.cfg-File"},
    {"766F6970636667207B0A2020202020202020756131207B0A20202020202020202020202020202020", "FFFFFFFFFFFFFFFFFFFFFFFFFFA8A8A0A6A080A080808080A0A08080A0A0A0A0808080908090A080",
     "-File"},

    {"626F783A73657474696E67732F6F706D6F64653D6F706D6F64655F7070706F650A636F6E6E656374", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8FBE6C4E08080E08080A0A080",
     "desc.txt-File"},
    {"7B0A6E616D653D22626C756577696E222C0A69643D22626C756577696E222C0A76697369626C653D", "FFF89BF0F3F7A7E08000008080808080808080808080800000808080808080808080808080808080",
     "desc.txt-File"},
    {"6D6F62696C65643A73657474696E67732F75652F61706E3D74656C737472612E636F72700A6D6F62", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3FAFDB68080A080808080808080A08080808080",
     "desc.txt-File"},

    {"308203E3308202CBA003020102021018D93D04728FCE2FBAA781A81F926A43300D06092A864886F7", "FFFFF808FFFFFE08FFFFFFFFFFFFEC800000B0804011000006010001400010CF8080C5C440B07A09",
     "CER-File"},
    {"B007F4570002000120001B1772696467655F72656365697665000000000100000013646F63736973", "FFFFFFFFFFFFFFFFFFFFE008BBA7E29890808598809890809AFFFFFFFFFECACFFFE89B809488928C",
     "Module-File"},

    {"5B556E69745D0A4578656353746172743D2F6574632F626F6F742E642F636F72652F636F6E666967", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4FEF9FFFFFFFFEEF3A3F9B1E0E080C08080",
     "service-File"},
    {"5B536572766963655D0A4265666F72653D6476622E736572766963650A41667465723D646F637369", "FFFFFFFFFFFFFFFFFFFFF8E0ECF1DEA6A2E0E4A0A0C0E0A0A0A0E0E08080E080808080A0E0808080",
     "service-File"},

};

Das funktioniert eigentlich recht gut. Zumindest besser als ich erwartet habe.
Man könnte noch hinzufügen das nach dem ersten Fund beendet wird. Aber das sind alles so nebensachen mit denen ich mich nicht noch zwei weitere Wochen beschäftigen wollte...
Ich hab auch noch keine Idee wie man das noch schöner machen könnte.

Jedenfalls kann ich nun mit fb_magic 5B536572766963655D0A4265666F72653D6476622E736572766963650A41667465723D646F637369
den Dateityp bekommen.
Bash:
fb_magic=0.0.0-10
FB_MAGIC="service-File"

Nu geht das eigentlich weiter mit dem parsen der ganzen unterschiedlichen Dateien. Ziel ist ja nach wie vor alles an Infos in eine Datenbank zu bekommen.
Soll ich da für jeden Dateityp nen eigenes Thema auf machen? wäre am besten oder?

Ah so, ich forgotten... Ich hab mit meiner Methode leichte Probleme mit der endianess... Da fällt mir auch so spontan erst ma nix zu ein.
 
Zurück
Oben Unten