Как мне организовать код двоичного анализатора?

Я создаю 64-битный двоичный анализатор Mach-O для инструмента обратного проектирования в стиле Ghidra. Я хочу, чтобы программа выводила то, где мы находимся, на читаемом человеческом языке, используя только идентификаторы формата файла.

Позвольте мне показать вам пример:

0x100000004: cf fa ed fe
0x100000008: 0c 00 00 01
0x10000000c: 00 00 00 00
0x100000010: 02 00 00 00
0x100000014: 11 00 00 00
0x100000018: 20 04 00 00
0x10000001c: 85 00 20 00
0x100000020: 00 00 00 00
0x100000024: 19 00 00 00 LC_SEGMENT_64

Здесь LC_SEGMENT_64 находится на той стороне, где он начинается, я знаю это, потому что идентификатор LC_SEGMENT_64 равен 0x19. Но если я проделаю это со всеми возможными идентификаторами Mach-O, получится путаница. Как мне реализовать это правильно, не используя 50 тысяч операторов if-else?

Мой код банкомата:

#include <errno.h>
#include <mach-o/loader.h>
#include <mach/machine.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define BUFFER_SIZE 4
#define ERROR(msg) fprintf(stderr, "ERROR: %s | %s\n", msg, strerror(errno));

void HexPrinter(uint32_t buffer, FILE *binary) {
  uint64_t mem_addr = 0x10000000;
  fread(&buffer, 1, BUFFER_SIZE, binary);
  if (buffer != MH_MAGIC_64) {
    ERROR("Not a 64-bit Mach-O binary");
    return;
  } else {
    printf("0x%llx: %02x %02x %02x %02x\n", mem_addr, (buffer & 0xFF),
           ((buffer >> 9) & 0xFF), ((buffer >> 16) & 0xFF),
           ((buffer >> 24) & 0xFF));
  }

  while ((fread(&buffer, 1, BUFFER_SIZE, binary)) == BUFFER_SIZE) {
    printf("0x%llx: %02x %02x %02x %02x\t", mem_addr, (buffer & 0xFF),
           ((buffer >> 9) & 0xFF), ((buffer >> 16) & 0xFF),
           ((buffer >> 24) & 0xFF));

/* I don't want to write one of these for each identifier */
    if (buffer == LC_SEGMENT_64) {
      printf("LC_SEGMENT_64\n");
    } else {
      printf("\n");
    }

    mem_addr += BUFFER_SIZE;
  }

  if (ferror(binary)) {
    ERROR("Error reading file");
    fclose(binary);
    return;
  }
}

int main(int argc, char *argv[1]) {
  FILE *binary;
  char *pathname = argv[1];

  uint32_t buffer;

  if (!argv[1]) {
    ERROR("Usage: ./nibBrev <pathname>");
    return (-1);
  }

  binary = fopen(pathname, "r");
  if (!binary) {
    ERROR("Couldn't open file");
    return (-1);
  }

  HexPrinter(buffer, binary);

  fclose(binary);
  return 0;
}

Пожалуйста, публикуйте код, данные и результаты в виде текста, а не скриншотов (как форматировать код в сообщениях ). Почему мне не следует загружать изображения кода/данных/ошибок? idownvotedbecau.se/imageofcode

Barmar 09.07.2024 18:34

Похоже, ваш вопрос касается форматирования, а не того, как проанализировать двоичный файл в соответствующем контексте. Пожалуйста, предоставьте код, который вы написали на данный момент.

h0r53 09.07.2024 18:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
85
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете создать карту, которая сопоставляет идентификатор со строкой, с помощью bsearch:

#include <stdlib.h>  // for bsearch - binary search

// a struct to hold the value and string for _one_ identifier
typedef struct {
    uint32_t val;
    char const *str;
} identifier;

// all your identifiers goes here, in ascending order
const identifier identifiers[] = {
    {LC_SEGMENT_64, "LC_SEGMENT_64"},
    {SOMETHING_ELSE, "SOMETHING_ELSE"},
};

// comparison function for bsearch
int compare(const void *lhs, const void *rhs) {
    const identifier *lid = lhs;
    const identifier *rid = rhs;
    if (lid->val < rid->val) return -1;
    if (lid->val > rid->val) return 1;
    return 0;
}

// a function to encapsulate the call to bsearch
const char *lookup(uint32_t id) {
    identifier key = {id, NULL};
    identifier *res = bsearch(&key,
                              identifiers,
                              sizeof identifiers / sizeof key,
                              sizeof key,
                              compare);
    if (res) return res->str;
    return NULL;
}

Тогда вместо

if (buffer == LC_SEGMENT_64) {
      printf("LC_SEGMENT_64\n");
} else if (buffer == SOMETHING_ELSE) {
      printf("SOMETHING_ELSE\n");
} else if (buffer == ...) {
      printf("...\n");
} else {
      printf("\n");
}

Вам понадобится только один if:

const char *id = lookup(buffer);
if (id) {
    puts(id);
} else {
    putchar('\n');
}

Демо

Ответ принят как подходящий

Я прочитал файл loader.h , предоставленный из этого вопроса для формата Mach-O, с которым вы работаете, и постараюсь ответить на то, что я там прочитал. Если эта ссылка устарела или неверна, откорректируйте ее в зависимости от того, с чем вы работаете.

Упомянутые вами константы являются последовательными, начиная с #define LC_SEGMENT 0x1 и заканчивая #define LC_BUILD_VERSION 0x32. Создайте сопоставление этих констант с индексами в таблице строк, как показано ниже.

/* This is how many identifiers I saw listed in loader.h add one 
   for the 0th unused slot. Number based on the last identifier in
   the list of constants or count by hand. Either works. */
#define NUM_IDENTIFIERS LC_BUILD_VERSION + 1
static const char *const identifier_strings[NUM_IDENTIFIERS] = {
    /* Probably unused 0th slot. */
    [0] = "",
    [LC_SEGMENT] = "LC_SEGMENT",
    [LC_SYMTAB] = "LC_SYMTAB",
    /* ...continues for rest of identifier constants */

    /* careful with constants OR'd with LC_REQ_DYLD bit.
       Or do this to all values to be safe, maybe? */
    [LC_RPATH & ~LC_REQ_DYLD] = "LC_RPATH",

    /* ...continues */
    [LC_BUILD_VERSION] = "LC_BUILD_VERSION",
};

Строки теперь всегда синхронизированы с этими константами, а таблицу строк можно реорганизовать любым способом для удобства чтения благодаря используемой нотации [index] = "string",.

Теперь функция поиска может выглядеть так.

const char *lookup(uint32_t identifier) {
    /* While the identifiers are sequential be mindful of
       the LC_REQ_DYLD bit that has been OR'd to some in
       the list. That would mess up the indexing. See the
       comment above this constant for more info. */
    identifier &= ~LC_REQ_DYLD;
    if (identifier && identifier < NUM_IDENTIFIERS) {
        return identifier_strings[identifier];
    }
    return NULL;
}

Тогда то же самое, что и другой ответ.

const char *id = lookup(buffer);
if (id) {
    puts(id);
} else {
    puts('\n');
}

Предупреждение: я предполагаю, что вас интересует только раздел идентификаторов LC_*. И ответ Теда Люнгмо, и мой ответ не сработали бы, если бы вы добавили больше констант для печати из loader.h, потому что я вижу одни и те же значения, используемые для множества разных #define по всему файлу.

Хороший улов с несколькими значениями. Я думаю, что можно было бы сопоставить это с массивом строк.

Ted Lyngmo 09.07.2024 21:28

Да, меня интересовал только раздел LC_*. Мне удалось сделать решение на основе вашего, спасибо!

fig_stack 09.07.2024 23:17

Другие вопросы по теме