Решил опубликовать исходный код C# для работы с форматом конфигураций 1С: Предприятие.


https://github.com/elisy/MdInternals


MdInternals понимает формат cf, cfu, epf, erf, распаковывает содержимое в удобочитаемые Xml и текстовые файлы и загружает обратно. Позволяет программно обращаться к внутренним файлам и свойствам объектов.


Проект состоит из частей:

  • MdInternals программно обращается к объектам и свойствам конфигурации
  • CfProject отвечает за сериализацию и десериализацию объектов MdInternals
  • MdInternals.Cil декомпилирует байт-код (OpCode) 1С
  • MdInternals.Serialization работает с внутренним полу-JSON форматом 1С вида "{ 19 { "", 2 } }"



Выгрузка файлов cf, cfu, epf, erf на диск


var cf = new CfPackage();
//или var cf = new EpfPackage();
//или var cf = new ErfPackage();
//или var cf = new CfuPackage();
cf.Open(@"D:\config.cf");
var project = new CfProject();
project.Save(epf, @"D:\Config\Xml\Config.cfproj", ProjectType.Xml);

Распознанные файлы записываются в дерево каталогов по видам объектов. Нераспознанные помещаются в каталог Unresolved:




Распознанные файлы выгружаются в XML-формате. Формат XML позволяет контролировать логическую целостность файлов и обрабатывать файлы сторонними программами. Известные свойства перемещаются в соответствующие разделы (атрибуты или тэги) XML-структуры:





Чтение из MSSQL-таблицы


var image = ImageReader.ReadImageFromConfig(@"data source=192.168.1.2\SQL2005;user=login;pwd=password;database=Database1C");


Обращение к внутренним файлам


var mp = new EpfPackage();
mp.Open(file);
var root = mp.MetadataObjects.Where(m => m.ImageRow.FileName == "root").FirstOrDefault();
var rp = new RootPointer(root.ImageRow);
var part = mp.MetadataObjects.Where(m => m.ImageRow.FileName == rp.MetadataPackageFileName.ToString()).FirstOrDefault();

Создание файла из выгруженного xml-формата


var project = new CfProject();
var mp = project.Load(@"D:\Config\Xml\Config.cfproj");
mp.Save(@"D:\config.cf");

Описание Cf-Формата


Cf-файл состоит из заголовка образа (ImageHeader) и следующими за ним страницами (ImagePage1-ImagePageN). Заголовок образа состоит из 4х байт сигнатуры, которая равна 0xFF 0xFF 0xFF 0x7F, 4х байт размера страницы и 8 зарезервированных байт. После заголовка файла идут по порядку страницы с данными. Каждая предыдущая страница ссылается на последующую.





Каждая страница (ImagePage) состоит из заголовка страницы (ImagePageHeader), группы указателей на записи ImageRowPointers и области ImageRows.





Заголовок страницы ImagePageHeader содержит в себе: зарезервированные 2 байта 0x0D 0x0A, 27 байт текстовой информации и еще зарезервированные 2 байта 0x0D 0x0A. Текстовая информация содержит 3 шестнадцатеричных числа: общий размер данных всех страниц (FullSize), размер текущей страницы (PageSize) и адрес следующей страницы в файле (NextPageAddress). FullSize проставляется только для первой страницы цепочки страниц. Для остальных страниц цепочки это значение 0. Для последней страницы цепочки NextPageAddress принимается равным 0xFF 0xFF 0xFF 0x7F.


Блок указателей ImageRowPointers занимает размер, указанный в значении PageSize страницы. Каждый указатель состоит из 4х байт адреса заголовка HeaderAddress и 4х байт адреса тела BodyAddress. В конце каждого указателя помещается сигнатура 0xFF 0xFF 0xFF 0x7F. Адреса указывают на расположения внутри текущей страницы на область ImageRows.


Заголовок ImageRowHeader начинается с блока заголовка страницы ImagePageHeader, который сообщает, сколько байт отведено под заголовок. Далее идут 20 зарезервированных байт, UTF-16 строка идентификатора данных (Id) и 4 зарезервированных байт.


Тело ImageRowBody начинается с блока заголовка страницы ImagePageHeader, который сообщает, сколько байт отведено под тело данных. Если тело данных начинается на 0xEF 0xBB 0xBF (сигнатура UTF8), то тело содержит UTF-8 строку. Иначе тело данных содержит упакованные данные. Если распакованные данные начинаются на 0xFF 0xFF 0xFF 0x7F, то содержимое – последовательность объектов, и они записаны в CF-формате. Иначе содержимое – это строка сериализации.



Что не реализовано


  • Утилита распознает только объекты конфигурации 1го уровня, помещая по подкаталогам. Не распознает остальное: формы, макеты, помещая в каталог Unresolved
  • В каталоге Unresolved не распаковываются составные объекты с расширением img
  • MdInternals распознает ограниченное числа свойств объектов

Комментарии (19)


  1. vis_inet
    02.01.2019 14:01

    Можете вкратце описать основные сценарии использования вашего продукта?


    1. Elisy Автор
      02.01.2019 14:18

      1. Чаще используют декомпилирование. В 1С возможна поставка конфигурации без исходного кода. Классы MdInternals.Cil восстанавливают исходный код из последовательности байт-кода OpCode 1С
      2. Восстановление поврежденных конфигураций
      3. Выгрузка конфигураций для средств версионирования. После выхода 1С 8.3 этот сценарий сомнительный. В 1С появилась опция выгрузки конфигурации в XML.
      4. Автоматизация труда разработчика. Например, автоинкрементация номера версии в свойствах конфигурации или установка текущей даты. После выхода 1С 8.3 этот сценарий сомнительный. В 1С появилась опция выгрузки конфигурации в XML.


  1. EvilBeaver
    02.01.2019 16:11

    Имхо, несколько поздновато, уже появились открытые аналоги, хотя, конечно и не такие, что все-в-одном, как у вас. Но тем не менее, все равно, спасибо.


    1. Elisy Автор
      02.01.2019 17:50

      Выложил, потому что несколько лет не доходили руки до проекта. Есть подозрение, что не дойдут. Может кому-то пригодятся алгоритмы. Смысла нет скрывать их от энтузиастов.


  1. ZEEGIN
    02.01.2019 17:23

    В 2011 (судя по скриншоту) это было актуально. Сейчас — кажется не очень.


    1. Elisy Автор
      02.01.2019 17:47

      Декомпилирование до сих пор очень востребовано. С выходом выгрузки в XML, вы правы, все поменялось. Есть подозрение, что работа напрямую с cf в памяти может быть намного быстрее, чем выгрузка в XML на диск, обработка и загрузка из XML с диска.


      1. ZEEGIN
        02.01.2019 17:51

        Я имею ввиду возмодность читать дерево метаданных прям из файлов cf и cfe во встроенном языке в 8.3.14.


        1. Elisy Автор
          02.01.2019 17:57

          Очень интересно. Можете дать наводку, как называется объект доступа к cf из 1С? Записывать тоже можно?


          1. ZEEGIN
            02.01.2019 18:00

            Реализована возможность анализа метаданных, расположенных в файлах .cf или .cfe. Реализован конструктор для объекта ОбъектМетаданныхКонфигурация.
            Реализована возможность получения имени конфигурации, номера версии и поставщика на основании файлов .cf или .cfe. Реализован объект ОписаниеКонфигурации.


            Реализована возможность получить из файла .cfu список версий конфигурации, которые могут быть обновлены данным обновлением, а также версию конфигурации, которая получится в результате обновления. Реализован объект ОписаниеОбновленияКонфигурации.


            Источник: http://downloads.v8.1c.ru/content//Platform/8_3_14_1494/1cv8upd_8_3_14_1494.htm#788ec9ef-0bf9-11e8-a3f7-0050569f678a


  1. ShoorickOff
    02.01.2019 17:42

    Декомпиляция нарушает лицензионное соглашение 1С.


    1. Elisy Автор
      02.01.2019 17:51
      +1

      Это не серьезное обвинение. Лично я не связан с 1С никакими обязательствами. Можно уточнить, что именно нарушает мой проект?


    1. Emelian
      02.01.2019 20:27

      > Декомпиляция нарушает лицензионное соглашение 1С.

      А обфускация байт-кода 1С не нарушает «лицензионное соглашение 1С»? А ведь некоторые фирмы распространяют подобные инструменты за деньги. А суть та же, что обфускация изменяет родной байт-код 1С, что деобфускация, или в данном случае простая декомпиляция кода защищенного стандартными средствами 1С? Аналогично архиваторы изменяют бинарный код и не только они, а ведь многие программы под лицензией «изменять бинарный код – ни-ни».

      А ведь достаточно очевидно, чтобы создать коммерческий продукт по обфускации байт-кода 1С, фирма должна научиться сначала его деобфусцировать / декомпилировать, ведь спецификации подобного формата нигде нет. Кроме того, авторы, которые покупают обфускатры и защищают свой код, пишут там такое! Например, тупо отслеживают действия пользователя и скрытно собирают его информацию (а это законно?) и даже открыто сообщают ему об этом, типа: «Я вижу, что ты пытаешься декомпилировать программу, лучше напиши мне – продам ее за полцены!».


  1. Emelian
    02.01.2019 20:48

    К сожалению, новизны здесь никакой нет. Даже «Классы MdInternals.Cil» которые «восстанавливают исходный код из последовательности байт-кода OpCode 1С» своей задачи явно не решают.

    Выгрузка штатными средствами конфигурации в файл и широко известные утилиты по декомпиляции (необфусцированного) байт-кода 1С плюс бывший в наличии (сейчас не проверял) онлайн-ресурс по декомпиляции байт-кода 1С полностью перекрывают все возможности данной программы.

    А «алгоритмы»? Кому они нужны, если они даже не демонстрируют простейших практических возможностей, хотя бы в той же «декомпиялции».

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


    1. Elisy Автор
      03.01.2019 09:39

      К сожалению, новизны здесь никакой нет. Даже «Классы MdInternals.Cil» которые «восстанавливают исходный код из последовательности байт-кода OpCode 1С» своей задачи явно не решают.

      Статистика использования онлайн декомпилирования говорит об обратном.

      бывший в наличии (сейчас не проверял) онлайн-ресурс по декомпиляции байт-кода 1С полностью перекрывают все возможности данной программы

      Если имеется ввиду онлайн-ресурс www.1csoftware.com/dotnet/en-us/decompiler, то он работает и под капотом у него один-в-один выложенный мной проект MdInternals.Cil.

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

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


      1. Emelian
        03.01.2019 11:40
        +1

        > под капотом у него один-в-один выложенный мной проект MdInternals.Cil.

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

        > Я пробовал декомпиляторы .Net и C# над обфусцированным кодом. Не все справлялись с защитой.

        А что, есть и такие, что справляются?

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

        Это не обвинение, это сожаление.

        P.S. Пару слов насчет обфускации байт кода 1С8х. Последние версии коммерческих обфускаторов используют много новых приемов защиты. Однако нужно понимать, что для специалиста это все не слишком серьезно. Общая идея обфускации простая, используется функционально эквивалентный байт-код, который усложняет процесс его восстановления на уровне ЯВУ (языка высокого уровня). Это может осуществляться как за счет добавления избыточной топологии к исходному бинарному циклическому графу, так и за счет якобы шифрования строковых констант и т.п., вроде использования специфики конкретных команд байт-кода. Шифрование не слишком серьезно потому, что в том же модуле всегда присутствует (обфусцированная) функция дешифрования. А с избыточной топологией, в том числе и «мусорным» кодом, можно легко бороться известными аналитическими методами. Главное здесь то, что, согласно математической теореме: «Любые эквивалентные преобразования обратимы», а это означает принципиальную декомпиляцию обфусцированного байт-кода на уровне ЯВУ.

        А вот, скажем, на уровне синтаксиса, обфускация является синтаксически неэквивалентной, поэтому в этом смысле она необратима. И, действительно, невозможно восстановить удаленные комментарии и необратимо измененные пользовательские имена переменных, процедур и функций. Однако функционально эквивалентный код уровня ЯВУ всегда можно получить без особых проблем. Алгоритмы там настолько просты, что просто удивительно, что про них никто не знает или не говорит вслух. Я тоже промолчу. А вам достаточно подсказки насчет самой обратимости и существования простого алгоритма этой обратимости.


        1. Elisy Автор
          03.01.2019 12:03

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

          На специализированных 1С ресурсах статьи про декомпилирование блокируются. Поэтому упоминал здесь вскользь. Не знал, как Хабр отнесется к этой теме.

          А вам достаточно подсказки насчет самой обратимости и существования простого алгоритма этой обратимости.

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


        1. ValeriVP
          05.01.2019 11:26

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


  1. abdurohman
    03.01.2019 06:16

    А готовую версию программы сможете тоже выложить, для тех, кто не в курсе C#?


    1. Elisy Автор
      03.01.2019 09:43

      Обработка EPF входит в проект здесь
      github.com/elisy/MdInternals/tree/master/Elisy.CfProject
      файл Elisy.CfProject.epf
      Он требует компонент Elisy.NetBridge.
      Выложен также на Инфостарт:
      Декомпилирование доступно через веб-сервис здесь: www.1csoftware.com/dotnet/en-us/decompiler