# Формат файлов USR: хранение, распаковка и обратная упаковка **Проект:** `ric930-usrinfo` **Версия документа:** 1.1 **Дата:** 16 октября 2026 г. **Статус:** техническая спецификация, восстановленная методом реверс-инжиниринга (**неофициальная**) ## 1. Назначение и краткое описание Файл `.USR` данного типа содержит XML-документ, упакованный по схеме: ```text КОДИРОВАНИЕ +---------------------+ +---------------------+ +----------------------+ | XML: исходные байты | ---> | zlib (RFC 1950) | ---> | Побайтовое сложение | ---> .USR | Windows-1251 | | DEFLATE (RFC 1951) | | по модулю 256 | +---------------------+ +---------------------+ +----------------------+ ДЕКОДИРОВАНИЕ .USR ---> обратное побайтовое вычитание ---> zlib inflate ---> XML (те же байты) ``` Содержимое `.USR` **не** является непосредственно XML, архивом ZIP или GZIP. После снятия обфускации получается **один полный поток zlib** — с заголовком, DEFLATE-данными и контрольной суммой Adler-32. Здесь (достоверно не подтверждено) собственных полей `magic`, номера версии, длины, соли, IV, ключа, MAC либо таблицы смещений, сохранённой внутри `.USR`. Весь файл, включая zlib-заголовок и контрольную сумму, обрабатывается одной арифметической операцией. **Размер USR равен размеру обфусцированного zlib-потока.** Все исследованные образцы не содержат данных после конца zlib-потока. В распакованном XML находятся данные о конфигурации установки «КонсультантПлюс»: версии компонентов, сведения о системе, составе поставки и информационных банках. Это **содержимое**, а не заголовок бинарного контейнера. ## 2. Результаты исследования ### 2.1 Установленные факты 1. После арифметического преобразования файлов `.USR` получаются корректные потоки zlib, начинающиеся с `78 9C`. 2. zlib распаковывает оба потока без ошибки и с корректной Adler-32; после потока нет лишних байтов. 3. Полученные XML **побайтово совпадают** с эталонными файлами, расшифрованными оригинальной утилитой. 4. `ric930-usrinfo` распаковывает образцы идентично эталонам и осуществляет обратный переход `XML → USR → XML` **без потери XML-байтов**. Сами вновь созданные USR отличаются от эталонных по DEFLATE-представлению. ### 2.2. Что **не** полуичлось подтвердить - Полнота поддержки всех поколений USR. - Побайтовая идентичность USR, созданных произвольным zlib-компрессором, с USR, созданными оригинальной программой. ## 3. Бинарная организация USR-контейнера Пусть `U[0..N-1]` — байты файла `.USR`; `Z[0..N-1]` — байты потока **zlib** после снятия обфускации; `X[0..M-1]` — исходные байты XML. ```text СМЕЩЕНИЯ В ФАЙЛЕ .USR: 0 N-1 +-------------------------------------------------------------+ | U[0] U[1] U[2] ... U[N-1] | +-------------------------------------------------------------+ каждый байт подвергнут обфускации | v СМЕЩЕНИЯ В ВОССТАНОВЛЕННОМ ZLIB: 0 1 2 N-4 N-1 +------+------+----------------------------------------+--------+ | CMF | FLG | DEFLATE: сжатые XML-байты |ADLER32 | +------+------+----------------------------------------+--------+ 2 байта переменная длина 4 байта | zlib inflate v X[0..M-1] = байты XML ``` - **Нет собственного 4- или 8-байтового заголовка перед zlib:** операция начинается с `U[0]`, то есть с самого первого байта файла. - **Нет отдельного хвоста USR после zlib:** последние четыре байта zlib являются Adler-32, а в файле USR они тоже обфусцированы. - **Нет независимого поля длины XML в контейнере:** размер результата определяется распаковкой. - Порядок байтов самой обфускации не зависит от endian архитектуры; **Adler-32** внутри zlib хранится в big-endian (старший байт первым). - `.USR` следует обрабатывать как бинарный файл: нулевые байты, произвольные байтовые значения и кодировки текстовых файлов здесь не имеют значения. Важно: `99 EF` встречается в начале **ВСЕХ** примеров файлов, поскольку обфусцирован заголовок `78 9C`. Это **не универсальная сигнатура всех USR**: другие корректные заголовки zlib могут дать другие первые два байта. ## 4. Побайтовая обфускация: точная формальная спецификация ### 4.1. Константы | Параметр | Hex | Decimal | Значение | |---|---|---:|---| | Начальное смещение `A` | `0x21` | 33 | Первый аддитивный байт | | Шаг `B` | `0x32` | 50 | Приращение после каждого байта | | Модуль | `0x100` | 256 | Арифметика беззнакового байта | | Начальный индекс | `0x00` | 0 | Отсчёт от начала файла | Для индекса `i = 0, 1, ..., N-1`: **Декодирование (USR → zlib):** ```text K(i) = (0x21 + 0x32 * i) mod 256 Z[i] = (U[i] - K(i)) mod 256 ``` **Кодирование (zlib → USR):** ```text K(i) = (0x21 + 0x32 * i) mod 256 U[i] = (Z[i] + K(i)) mod 256 ``` Рекуррентная запись, удобная для потоковой реализации: ```text offset = 0x21 для каждого байта: decode: z = uint8(u - offset) encode: u = uint8(z + offset) offset = uint8(offset + 0x32) ``` **Ключевой момент:** `offset` **нельзя сбрасывать при чтении очередного буфера**; он обновляется непрерывно от начала файла до его конца. Индекс также начинается заново при обработке **следующего файла**. ### 4.2. Период последовательности Поскольку `gcd(50, 256) = 2`, наименьший период равен `256 / 2 = 128`: ```text K(i + 128) = K(i) ``` Первые смещения: ```text 21 53 85 B7 E9 1B 4D 7F B1 E3 15 47 79 AB DD 0F ... (hex) ``` ## 5. Формат потока zlib внутри USR После снятия обфускации применяется **zlib** по RFC 1950, использующий **DEFLATE** по RFC 1951. ### 5.1. Структура zlib ```text CMF (1 байт) | FLG (1 байт) | [DICTID при FDICT=1] | DEFLATE | ADLER32 (4 байта) ``` ### 5.2. Содержимое DEFLATE DEFLATE использует повторяющиеся последовательности (LZ77) и коды Хаффмана. Он может содержать несколько блоков разных типов (без сжатия, с фиксированными или динамическими кодами). Подробный битовый формат определяется RFC 1951. ### 5.3. Adler-32 и контроль целостности Последние **4 байта восстановленного zlib-потока** содержат Adler-32 **распакованных XML-байтов** в порядке big-endian: ```text s1 = 1 s2 = 0 for each x in XML bytes: s1 = (s1 + x) % 65521 s2 = (s2 + s1) % 65521 Adler32 = (s2 << 16) | s1 ``` Adler-32 помогает обнаруживать **случайное повреждение** при хранении и передаче. ## 6. Использованные материалы и нормативные ссылки **Стандарты и справочная документация:** - RFC 1950, *ZLIB Compressed Data Format Specification version 3.3*: - RFC 1951, *DEFLATE Compressed Data Format Specification version 1.3*: - Go `compress/zlib`: - Go `compress/flate`: - Go `encoding/xml`: