Files
2026-10-16 21:11:50 +03:00

10 KiB
Raw Permalink Blame History

Формат файлов USR: хранение, распаковка и обратная упаковка

Проект: ric930-usrinfo
Версия документа: 1.1
Дата: 16 октября 2026 г.
Статус: техническая спецификация, восстановленная методом реверс-инжиниринга (неофициальная)

1. Назначение и краткое описание

Файл .USR данного типа содержит XML-документ, упакованный по схеме:

                                   КОДИРОВАНИЕ
+---------------------+      +---------------------+      +----------------------+
| 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.

СМЕЩЕНИЯ В ФАЙЛЕ .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):

K(i) = (0x21 + 0x32 * i) mod 256
Z[i] = (U[i] - K(i)) mod 256

Кодирование (zlib → USR):

K(i) = (0x21 + 0x32 * i) mod 256
U[i] = (Z[i] + K(i)) mod 256

Рекуррентная запись, удобная для потоковой реализации:

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:

K(i + 128) = K(i)

Первые смещения:

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

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:

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. Использованные материалы и нормативные ссылки

Стандарты и справочная документация: