Почему значение CRC для одного и того же участка кода изменяется при каждом перезапуске программы?

Как я могу улучшить контроль над CRC определенного участка кода, заключенного между метками begin и end, чтобы избежать его изменения при перезапуске программы? В этом участке кода происходит проверка пароля пользователя. Однако я заметил, что CRC меняется при некоторых запусках программы из-за изменений в байтах этого участка, что снижает его эффективность. Что я делаю неправильно?
  • 4 декабря 2024 г. 18:03
Ответы на вопрос 2
Значение CRC (циклический избыточный код) может изменяться при каждом перезапуске программы по нескольким причинам, даже если участок кода остаётся тем же. Вот некоторые возможные причины:

1. **Непредсказуемые данные:** Если участок кода содержит переменные (например, для пароля), которые могут меняться в процессе выполнения программы, это может влиять на результат CRC.

2. **Метаинформация:** Компиляторы могут генерировать различный код при каждом запуске из-за оптимизации, добавления отладочной информации и других факторов, что может влиять на байты между метками begin и end.

3. **Стек и динамическое выделение памяти:** Динамически выделяемые области памяти могут изменяться между запусками, что также может влиять на результат CRC, особенно если участок кода взаимодействует с этими данными.

### Как улучшить контроль над CRC:

1. **Изоляция кода:** Убедитесь, что код, зависящий от внешних переменных или состояний, полностью изолирован в рамках проверки CRC. Например, переменные, влияющие на код, должны быть фиксированы.

2. **Фиксация состояния:** Использование фиксированных состояний или данных, которые не изменяются между запусками. Это может быть особенно важно для участков кода, зависящих от пользовательского ввода или динамических данных.

3. **Фиксированный блок:** Составьте ваш код таким образом, чтобы он не зависел от состояния программы. Избегайте использования глобальных переменных и других источников нестабильных данных в пределах вашего контролируемого участка.

4. **Игнорирование диапазонов памяти:** Если вы используете инструменты, которые позволяют игнорировать часть памяти, например, сегменты, которые содержат переменные, которые не должны влиять на результат CRC, это поможет сохранить значение постоянным.

5. **Использование детерминированного генератора:** Для генерирования пароля или любых других динамических данных используйте стандартные и предсказуемые алгоритмы, а не случайные генераторы, которые могут выдавать разные значения на разных запусках.

### Пример кода:

Если у вас есть участок, где происходит проверка пароля, попробуйте следующий подход:

```c
// Пример: фиксированный участок кода для проверки пароля
const char* expected_password = "secure_password";

bool check_password(const char* input_password) {
    return strcmp(input_password, expected_password) == 0;
}

// Использование CRC
unsigned int crc_value = calculate_crc(&begin, &end); // Фиксируйте область с использованием begin и end
```

В данном примере алгоритм CRC будет более стабилен, поскольку его работа не зависит от изменяемых данных, что может помочь сохранить значение CRC неизменным между запусками.
Дело в том, что при загрузке программы загрузчик перезаписывает в ней всякие адреса, которые используются при вызовах функций и переходах. Это нужно из-за того, что программа-то может быть загружена по произвольному адресу. А некоторые команды процессора принимают абсолютный адрес. Так же всякие техники защиты вроде ASLR тут все дополнительно портят. У вас там функции библиотеки вызываются, а где они в памяти лежат - вы заранее узнать не можете. Вот и как минимум аргументы call в памяти оказываются разными. 

И защита ваша ничем не поможет, потому что можно пропатчить не только проверку пароля, но и проверку CRC.
Похожие вопросы