Как проанализировать обфусцированную функцию 1С и понять, что она возвращает, а также почему 1С не ругается на необъявленные метки?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с кодом на платформе 1С:Предприятие, особенно если он был подвергнут обфускации, мы можем столкнуться с трудностями в понимании его логики и определении результатов выполнения. Обфускация — это процесс преднамеренного запутывания кода с целью затруднить его анализ человеком, но при этом сохранить его функциональность. Давайте разберем пример такой функции, выясним, что она возвращает, и проанализируем особенности работы с метками перехода в языке 1С, которые часто используются в обфусцированном коде.

Анализ обфусцированной функции 1С и определение её возвращаемого значения

Перед нами стоит задача проанализировать следующую обфусцированную функцию 1С, представленную в исходном сообщении, и определить, какое значение она возвращает. Функция выглядит следующим образом:


Функция aaa__a
  ~0:_0 = 1; _1 = 0; _0 = _0  _1;
  Если _0 = Ложь Тогда Перейти ~ME_101; КонецЕсли;
  Перейти ~6;
  ~ME_101:Перейти ~9;
  ~1:_0 = 1; _0 = -_0; a = _0;
  ~3:_0 = 73; Возврат _0;
  ~5:_0 = 74; Возврат _0;
  ~6:_0 = 0; _1 = 0; _0 = _0 >= _1; Если _0 = Ложь Тогда Перейти ~ME_102; КонецЕсли; Перейти ~4;
  ~ME_102:Перейти ~13;
  ~7:_0 = 1; a = _0;
  ~8:_0 = 1; _0 = -_0; a = _0; Перейти ~5;
  ~9:_0 = 1; _0 = -_0; _1 = 0; _0 = _0 >= _1; Если _0 = Ложь Тогда Перейти ~ME_103; КонецЕсли; Перейти ~12;
  ~ME_103:Перейти ~2;
  ~10:_0 = 0; a = _0;
  ~11:_0 = 1; _0 = -_0; a = _0;
  ~12:Перейти ~14;
  ~13:Перейти ~0;
КонецФункции

Первое, что мы замечаем, это нестандартные имена переменных (_0, _1, a) и меток (~0, ~ME_101), а также активное использование оператора Перейти. В строке _0 = _0 _1; отсутствует оператор сравнения или арифметическая операция. Однако, основываясь на анализе в сообщении 17 форума, мы можем предположить, что здесь подразумевается оператор меньше или равно (<=), и результатом этого сравнения будет булево значение.

Давайте пошагово проанализируем выполнение функции, чтобы определить её возвращаемое значение. Мы будем следовать логике, которая привела к правильному ответу в обсуждении на форуме (сообщение 17), несмотря на выявленные расхождения с оригинальным текстом функции из сообщения 1. Эти расхождения могут быть следствием ошибок при копировании, или обфускатор мог использовать более сложную логику, которую трудно полностью воспроизвести в простом текстовом листинге. Тот факт, что автор темы принял результат "74" как верный, позволяет нам сосредоточиться на пути, ведущем к этому значению.

  1. Старт функции, метка ~0:
    
    ~0:_0 = 1;
    _1 = 0;
    _0 = _0 <= _1; // Предполагаем оператор "<="
    

    На этом шаге переменная _0 становится 1, а _1 становится 0. Затем выполняется сравнение 1 <= 0, которое дает результат Ложь. Таким образом, переменной _0 присваивается значение Ложь.

  2. Проверка условия: Если _0 = Ложь Тогда Перейти ~ME_101; КонецЕсли;

    Поскольку _0 равно Ложь, условие истинно, и управление должно было бы передаться на метку ~ME_101. Однако, чтобы функция вернула значение 74 (как указано в сообщении 17), фактический путь выполнения должен был пройти через метку ~7, а затем перейти на ~5. Исходя из принятого результата, мы делаем допущение, что в реальном коде (или его логическом представлении) происходит переход к метке ~7.

  3. Предполагаемый путь к ~7:

    Мы будем следовать пути, который приводит к результату 74. Это подразумевает, что после условия на метке ~0, управление каким-либо образом передается на метку ~7.

    
    ~7:_0 = 1;
    a = _0; // Переменной 'a' присваивается значение 1.
    

    Здесь переменной _0 присваивается 1, и это значение далее присваивается переменной a.

  4. Переход на ~8:
    
    ~8:_0 = 1;
    _0 = -_0; // _0 становится -1.
    a = _0;    // Переменной 'a' присваивается значение -1.
    Перейти ~5;
    

    На метке ~8 переменная _0 сначала устанавливается в 1, затем ее значение инвертируется, и _0 становится -1. Это значение также присваивается переменной a. После этого происходит безусловный переход на метку ~5.

  5. Финальный переход на ~5 и возврат значения:
    
    ~5:_0 = 74;
    Возврат _0;
    

    На метке ~5 переменной _0 присваивается значение 74, и функция немедленно возвращает это значение.

Таким образом, функция aaa__a возвращает значение 74. Переменная a изменяла свое значение в процессе выполнения, но ее финальное значение не влияет на возвращаемый функцией результат.

Почему 1С не "ругается" на необъявленные метки безусловного перехода?

Вопрос о том, почему платформа 1С:Предприятие не выдает ошибку на "необъявленные" метки, является важным аспектом понимания языка 1С. Ответ кроется в особенностях синтаксиса и работы оператора Перейти (GoTo).

  1. Метки не требуют предварительного объявления: В языке 1С метки безусловного перехода (такие как ~0:, ~ME_101:, ~6:) не требуют отдельного предварительного объявления, подобно переменным или процедурам. Они определяются самим фактом их использования в коде с двоеточием после идентификатора.
  2. Компилятор 1С распознает метки: При компиляции модуля платформа 1С:Предприятие сканирует код и строит таблицу всех определенных меток в пределах текущего модуля. Когда она встречает оператор Перейти ИмяМетки;, она проверяет, существует ли ИмяМетки: где-либо в этом же модуле. Если метка найдена, компиляция продолжается. Если метка не найдена, только тогда будет выдана ошибка "Метка не найдена".
  3. Синтаксис меток: Метка — это просто идентификатор, за которым следует двоеточие. Любой допустимый идентификатор (сочетание букв, цифр и знаков подчеркивания, начинающееся с буквы или знака подчеркивания) может быть меткой. Префикс ~, как в нашем примере (~ME_101), хоть и нетрадиционен для обычного программирования, является абсолютно допустимым символом в идентификаторах 1С и часто используется обфускаторами для создания непривычных имен.
  4. Область видимости меток: Метки являются локальными для того модуля, в котором они определены. Нельзя перейти на метку, которая находится в другом модуле.

Таким образом, необъявленные метки не вызывают ошибок, потому что они не требуют объявления; они просто должны существовать в тексте модуля, чтобы на них можно было сослаться. В нашем случае, все используемые метки (за исключением потенциальной ~2, которая по анализу не была достигнута) были фактически определены в теле функции.

Обфускация в 1С: Методы, цели и инструменты

Обфускация, или запутывание кода, является распространенной практикой в разработке программного обеспечения, в том числе и для 1С. Давайте рассмотрим ее основные аспекты, чтобы глубже понять природу таких функций, как та, которую мы анализировали.

Методы обфускации кода 1С

Обфускация в 1С выходит за рамки простого использования оператора Перейти и может включать в себя множество техник для усложнения анализа кода. Мы рассмотрим наиболее часто встречающиеся:

  1. Переименование идентификаторов: Одним из основных методов является замена осмысленных имен переменных, процедур, функций, объектов и модулей на бессмысленные комбинации символов (например, _0, _1) или случайно сгенерированные идентификаторы (aaa__a). Это значительно затрудняет понимание предназначения каждого элемента кода.
  2. Удаление форматирования: Для усложнения чтения кода обфускаторы удаляют переносы строк, пробелы, табуляции, а также все комментарии. Весь текст может быть приведен к одному регистру (например, строчному). Это делает код монолитным и крайне трудночитаемым.
  3. Шифрование строковых констант: Все текстовые строки, присутствующие в коде (например, сообщения для пользователя, запросы к базе данных, имена метаданных), преобразуются в зашифрованный вид. Часто для этого используются случайные ключи, что делает текстовые данные нечитаемыми в исходном коде и затрудняет поиск ключевых слов или анализ бизнес-логики.
  4. Изменение логики выполнения:
    • Разрушение типовых конструкций: Стандартные и легко читаемые структурированные операторы (такие как Если..Тогда..КонецЕсли, Для Каждого..Цикл, Пока..Цикл) могут быть преобразованы в сложную последовательность безусловных переходов (Перейти). Это значительно запутывает поток выполнения программы.
    • Создание ложных условных и безусловных переходов: В код могут быть добавлены переходы на участки, которые никогда не будут достигнуты при нормальном выполнении или не несут функциональной нагрузки. Такие "тупиковые" ветви увеличивают сложность графа управления и затрудняют трассировку.
    • Добавление фиктивных операций и выражений: В код могут быть вставлены ничего не значащие операции или выражения, которые увеличивают его объем, но не влияют на основную логику работы. Это заставляет аналитика тратить время на изучение бесполезных участков кода.
  5. Кодирование чисел: Числовые константы, вместо прямого указания, могут быть представлены в виде строковых значений и декодированы в числа только во время выполнения, что еще больше затрудняет понимание числовой логики.
  6. Компиляция в байт-код стековой машины: Некоторые более продвинутые обфускаторы могут преобразовывать текст модулей в свой собственный байт-код стековой машины. Это радикально меняет структуру кода, делая его практически нечитаемым и чрезвычайно сложным для обратного инжиниринга.

Цели обфускации кода 1С

Основная цель обфускации — защита интеллектуальной собственности разработчика. Мы можем выделить несколько конкретных целей применения обфускации:

  1. Защита алгоритмов и бизнес-логики: Это включает в себя защиту уникальных алгоритмов, ноу-хау и ключевой бизнес-логики от несанкционированного копирования, изучения и использования конкурентами или недобросовестными пользователями.
  2. Защита демо-версий продуктов: Обфускация позволяет передавать клиенту полнофункциональное демонстрационное решение с ограничениями по сроку действия, среде исполнения или привязкой к конкретному оборудованию. Это стимулирует клиента к полной оплате за продукт, поскольку он не может просто "сломать" или скопировать демо-версию.
  3. Затруднение сопровождения, изменения и тиражирования: Обфускация делает код крайне сложным для понимания, что предотвращает его легкое изменение, адаптацию или тиражирование сторонними специалистами без ведома и разрешения разработчика.
  4. Предотвращение несанкционированного проникновения: Обфускация может затруднить поиск уязвимостей или "дыр" в безопасности системы, поскольку атакующему значительно сложнее понять внутреннюю структуру и логику кода.
  5. Защита байт-кода 1С от декомпиляции: Актуально для защиты от известных и новых декомпиляторов, которые могли бы восстановить исходный текст из скомпилированных модулей 1С.

Инструменты для обфускации 1С

Для обфускации кода 1С существуют как встроенные возможности платформы, так и сторонние решения, которые мы рассмотрим:

  1. Встроенные средства 1С:
    • 1C:Enterprise Compiler: Этот инструмент интегрирован в среду разработки 1С и может участвовать в процессе подготовки и компиляции кода, предлагая базовые уровни защиты.
    • 1C:Enterprise Obfuscator: Это отдельный инструмент, разработанный компанией 1С специально для обфускации кода конфигураций.
    • 1C:Enterprise Protect: Представляет собой комплексное решение от 1С, которое обеспечивает не только обфускацию, но и другие механизмы защиты от несанкционированного доступа и копирования.
  2. Сторонние решения:
    • Коммерческие продукты: На рынке представлены платные решения, такие как "Нетленка: Защита конфигураций 1С". Они используют множество продвинутых методов для защиты как исходных текстов, так и байт-кода 1С.
    • Внешние обработки: Существуют специализированные внешние обработки, которые распространяются через различные платформы (например, Infostart или GitHub). Эти обработки позволяют выполнить обфускацию выбранных модулей или всей конфигурации.

Ограничения и недостатки обфускации

Несмотря на свои преимущества, обфускация не является стопроцентной защитой и имеет ряд существенных недостатков, которые мы должны учитывать:

  1. Не 100% защита: Хотя обфускация значительно усложняет анализ, высококвалифицированные специалисты, имеющие достаточные ресурсы и время, могут в конечном итоге де-обфусцировать код и восстановить его исходную логику. Обфускация — это скорее препятствие, чем абсолютный барьер.
  2. Значительное усложнение сопровождения и отладки: Обфусцированный код становится чрезвычайно трудным для чтения, понимания, отладки и последующей модификации. Для разработчика работа с собственным обфусцированным кодом может стать такой же сложной, как и для стороннего аналитика, что увеличивает затраты на поддержку продукта.
  3. Безвозвратная потеря информации: В процессе обфускации теряется ценная информация, такая как исходные, осмысленные имена методов, переменных, процедур, а также все комментарии и исходное форматирование кода. Это делает восстановление читаемого кода крайне трудоемким процессом, который по сложности может быть сравним с изначальной разработкой.
  4. Отсутствие встроенного механизма лицензирования: Сама по себе обфускация не предоставляет механизмов лицензирования. Для контроля использования продукта (например, привязка к оборудованию, ограничения по сроку действия) требуются отдельные, специализированные решения, которые часто комбинируются с обфускацией.
  5. Возможность обхода штатных методов защиты: Некоторые штатные методы защиты 1С, например, установка пароля на модуль, могут быть обойдены с помощью специализированных декомпиляторов или утилит, что требует использования более сложных методов обфускации для реальной защиты.

Таким образом, обфускация — это мощный инструмент для защиты интеллектуальной собственности, но ее применение требует тщательного взвешивания всех "за" и "против", учитывая потенциальные сложности в дальнейшем сопровождении и развитии решения. Она создает значительное препятствие для анализа, но не гарантирует абсолютной невозможности взлома.

← На главную