Необычный случай восстановления данных или немного реверс-инжиниринга PLC Siemens Simatic S7-300
На вопрос, какие не самые обычные случаи восстановления данных могут повстречаться в компании, профиль которой — извлекать информацию из поврежденных накопителей, можно привести пример одной из недавних задач с MMC картой из промышленного ПЛК (PLC) Siemens Simatic S7 300, в задачи которого входило управление несколькими десятками электродвигателей и клапанов, а также анализ параметров целой россыпи датчиков некоего конвейера.
Для решения этой задачи перечень услуг специалиста по работе с поврежденными накопителями оказался недостаточным. Кроме этого потребовался опыт реверс-инженера, опыт аналитика повреждений в данных, не имеющих избыточности, а также опыт программиста.
Все началось с того, что в один из сентябрьских дней поступил звонок в офис нашей компании. Вопрос клиента состоял в том, готовы ли мы восстановить данные с MMC карты, на которой используется проприетарная файловая система. На вопрос о том, что случилось с картой, клиент ответил, что есть несколько нечитаемых секторов. Также клиент поинтересовался, знакомы ли мы с промышленными программируемыми логическими контроллерами от Siemens, на что получил ответ, что не знакомы, но можем попытаться исследовать устройство файловой системы и масштаб проблем и далее попытаться найти способ решения.
Клиент не особо был воодушевлен этим ответом и засомневался, стоит ли везти карту памяти в наш офис для проведения аналитических мероприятий. Было предложено прислать посекторную копию для анализа и даны разъяснения как ее можно получить средствами, доступными пользователю.
Получив файл-образ флеш карты, приступаем к осмотру в шестнадцатеричном редакторе.
Рис. 1. LBA 0 (MBR) из образа ММС карты
Первое, что бросается в глаза в начале образа — это предупреждение «Original Siemens Equipment. Use only with Siemens SIMATIC. Do not format or partition.» Не обнаружено признаков кода загрузчика, который обычно присутствует в устройствах на х86. В таблице разделов присутствуют 4 шестнадцатибайтных записи о разделах по смещениям 0×1BE, 0×1CE, 0×1DE, 0×1EE. Тип раздела 0×73 до этого случая не встречался.
При переходе по смещению на начало первого раздела, описанного в таблице, наблюдаем признаки каких-то данных, но структура и назначение неизвестны.
Рис. 2. LBA 1 — начало первого раздела, описанного в таблице.
Также в границах раздела обнаруживается множество секторов с ненулевым заполнением и некоторым сходством по заполнению.
В границах второго и третьего разделов отсутствуют признаки данных, отличных от нуля.
По смещению на начало четвертого раздела обнаруживаем данные, похожие на некий идентификационный блок.
Рис. 3. LBA 31 328 — начало четвертого раздела.
Иных данных, отличных от нуля, на этом разделе более нет. Очевидно, что разделы 2, 3, 4 можно исключить из дальнейшего рассмотрения по причине отсутствия какого-либо значимого содержимого.
В границах первого раздела выполняем поиск каких-либо известных метаданных файловых систем средствами DataExtractorиз комплекса PC3000Express. Результаты поиска неутешительны — никаких известных структур не обнаружено.
В такой ситуации поясняем клиенту, что действительно на накопителе нет признаков известных файловых систем, и самым бюджетным методом будет попытка чтения флеш-накопителя нашими средствами. Возможно, при определенных условиях нечитаемые у клиента блоки буду прочитаны, и это будет решением задачи.
Клиент, изучив рынок услуг, не обнаружил предложений, альтернативных нашему, где бы предлагались более действенные методы решения задачи и в итоге принял предложение предоставить ММС карту для осуществления попыток чтения.
Рис. 4. PLC Siemens SIMATIC S7–300 и карта памяти MMC.
Было предпринято множество попыток прочитать карту, и некоторые из них были успешны, согласно протоколу передачи данных от карты к ридеру. Но после проведения сравнительного анализа «успешных» попыток чтения оптимизма в плане решения задачи поубавилось.
Рис. 5. Разночтения при «успешных» попытках чтения.
Обнаружилось, что начитанное из одних и тех же мест содержимое сильно различается. Очевидно, что микропрограмма карты памяти при большом количестве битовых ошибок способна отдать искаженные данные под видом успешно прочитанных.
Ничего не остается, как рассмотреть возможные методы исправления ошибок. Первое, что обычно практикуется в борьбе со случайно возникающими ошибками, — это многократная вычитка поврежденных участков с последующим выбором наиболее часто повторяющихся значений. Недостаток этого метода проявляется в местах, которые устойчиво читаются с ошибкой. В итоге в скомпонованный вариант попадают ошибочные данные.
В нашем случае после анализа нескольких скомпонованных вариантов становится очевидным, что данный метод без дополнительной аналитики неприменим из-за сохраняющихся разночтений в скомпонованных вариантах. На этом моменте появляется необходимость ознакомления с ПЛК Siemens Simatic S7–300.
Обращаемся к сайту производителя за документацией и обнаруживаем достаточно большой документ размером около 300 страниц, на изучение которого может потребоваться слишком много времени. Поиск альтернативных материалов привел к нахождению учебно-методического пособия «Основы языка программирования STEP7 и базового программного обеспечения промышленных контроллеров SIEMENS» Автор: Романов В.П., которое оказалось более пригодным для быстрого ознакомления с общей идеологией написания программ для контроллеров. Этого пособия и накопленных ранее знаний было достаточно, чтобы приступить к дальнейшим исследованиям.
Рис. 6. Среда разработки WinSPS-S7 с открытым декомпилированным проектом.
Прикладное программное обеспечение, исполняемое в среде PLC Siemens Simatic S7 делится на блоки различного назначения:
OB — организационные блоки, которые являются обработчиками событий.
FC — функциональные блоки, которые можно вызывать с передачей параметров.
FB — функциональные блоки, отличаются от FC возможностью использовать STAT переменные.
DB — блоки данных.
SFC — системные функциональные блоки.
SFB — системные функциональные блоки.
SDB — системные блоки данных.
Рассмотрим один из блоков в виде декомпилированного кода и в откомпилированном варианте.
Рис. 7. Функциональный блок FB5 в откомпилированном варианте.
Обращаем внимание, что кроме самого кода присутствуют описатели типов переменных, а также присутствует деление кода на сегменты (networks). Это не совсем свойственно для языков, похожих на ассемблер. Это наблюдение дает нам основания полагать, что это не вольная трактовка среды разработки, а наличие служебных данных, которые описывают переменные и сегменты кода.
Для проверки предположений нам необходимо посмотреть в откомпилированном блоке размер всех инструкций и определить те места, которые не являются непосредственно исполняемым кодом. Для выполнения этой задачи необходим справочник, где были бы указаны шестнадцатеричные коды и размерность операндов, соответствующие мнемоникам. Быстро найти такой справочник в официальной документации не удалось, но на просторах интернета обнаружены труды Nick Naumenko, опираясь на которые можно было продолжить анализ.
Рис. 8. Откомпилированный функциональный блок FB5.
По смещению 0×24 обнаруживаем последовательность байт 0×79 0×58 0×00 0×02, где 0×79 0×58 инструкция «А», а 0×00 0×02 — её операнд. По смещению 0×9Cнаходится последовательность байт 0×65 0×00, что соответствует инструкции BE (Blockend), по достижении которой выполнение кода в блоке завершается, и возвращается управление в блок, откуда был осуществлен вызов. Как видим, размер исполняемого кода заметно меньше, чем всего информации в блоке, и составляет 0×7A (122) байта при размере всего блока 0xFA (250) байт. Сразу бросается в глаза значение 0×00 0×7Aпо смещению 0×22, которое равно размеру исполняемого кода, и значение 0×00 0xFAпо смещению 0×0A, которое равно размеру всего блока. Проверки на других блоках подтверждают предположение о назначении этих байт. Проведя множество сравнительных и аналитических операций, выяснили назначение большинства данных, не являющихся исполняемым кодом.
Устройство блока.
Смещение | Размер | Описание |
0×00 | DWORD | Устойчивое выражение 0×70 0×70 0×01 0×10 — маркер начала блока |
0×04 | BYTE | Данное значение изменяется при перезаписи блока средствами контроллера. Возможно, счетчик. Дублируется в файловой системе. |
0×05 | BYTE | Тип блока (0×0С — FC, 0×0E — FB, 0×0A — DB и т.п.) |
0×06 | WORD | Номер блока |
0×0A | WORD | Размер блока |
0×10 | 6 BYTES | Метка времени (timestamp) — дата и время создания |
0×16 | 6 BYTES | Метка времени (timestamp) — дата и время последних исправлений |
0×1C | WORD | Размер label area (блок описания типов переменных и установленных значений) |
0×1E | WORD | Размер таблицы сегментов |
0×22 | WORD | Размер исполняемого кода. |
0×24 | [0×22] | Начало исполняемого кода. |
[0×22]+0×24 | [0×1C] | Label Area — блок описаний типов переменных и их значений. Начало блока вычисляется посредством сложения 0×24 с значением по смещению 0×22 |
[0×1C]+[0×22]+0×24 | [0×1E] | Таблица количества и размеров сегментов кода (Networks) |
[0×1E]+[0×1C]+[0×22]+0×24 | Информационный блок |
Устройство таблицы переменных (Label Area)
Смещение | Размер | Описание |
0×02 | WORD | Размер описателей типов переменных |
0×04 | WORD | Размер блока с установленными значениями переменных значений переменных |
0×07 | [0×02] | Блок описания типов переменных. На описание каждой переменной выделяется 2 байта. В первом байте указывается тип переменной (0×01 — bool, 0×02 — byte, 0×05 — int, 0×08 — real и т.п.). Во втором байте указывается статус переменной: не определен, определен, имеет фиксированное значение в блоке значений переменных |
[0×02]+0×07 | [0×04] | Блок значений переменных |
Устройство таблицы сегментов кода (Networks)
Смещение | Размер | Описание |
0×00 | WORD | Количество сегментов кода |
0×02 | [0×00]*2 | Записи размеров сегментов. Каждая запись состоит из двух байт. |
Устройство информационного блока
Смещение | Размер | Описание |
0×00 | QWORD | Текстовое поле «Author» |
0×08 | QWORD | Текстовое поле «Family» |
0×10 | QWORD | Текстовое поле «Name» |
0×18 | BYTE | Номер версии. Старшие 4 бита — номер перед точкой, младшие 4 бита — номер после точки |
Для решения задачи по восстановлению данных кроме анализа содержимого модулей ПО к PLC Siemens SIMATIC S7 необходимо частично исследовать файловую систему, чтобы понимать принцип размещения данных, с дальнейшей разработкой методов контроля целостности.
При осмотре данных в образе карты памяти обнаруживается, что в каждом секторе первого раздела выделяются первые 16 байт под нужды файловой системы, а 496 байт — для хранения данных. В первом секторе раздела содержатся конфигурационные параметры, один из которых является ссылкой на таблицу объектов.
Устройство служебного заголовка в секторе
Смещение | Размер | Описание |
0×00 | BYTE | Данное значение изменяется при перезаписи блока средствами контроллера. Возможно, счетчик. Дублируется в заголовке блока |
0×01 | BYTE | Тип блока |
0×02 | WORD | Номер блока |
0×04 | WORD | Порядковый номер сектора в сохраненном объекте |
0×0A | WORD | Абсолютный номер следующего сектора, принадлежащего текущему объекту. 0×00 — признак последнего сектора в цепочке. |
0×10 | Пользовательские данные |
Рис. 9. Конфигурационный сектор
В конфигурационном секторе по смещению 0×2A находится абсолютный указатель на начало таблицы размещения объектов (получаемое смещение в байтах 0×0152*0×0200=0×2A400).
Рис. 10.Таблица размещения объектов
По рисунку 10 достаточно легко заметить, что размер одной записи в таблице составляет 16 байт.
Устройство записи в таблице размещения объектов.
Смещение | Размер | Описание |
0×01 | BYTE | Тип блока |
0×02 | WORD | Номер блока |
0×06 | WORD | Размер данных блока (дублируется в заголовке блока) |
0×0A | WORD | Абсолютный номер первого сектора блока |
Опираясь на приведенные выше данные в таблицах, имеем возможность разработать методы логической коррекции ошибок.
Первым шагом было приведение в порядок всех секторных заголовков в поврежденных местах, чтобы начала отрабатывать процедура конвертации из образа MMC карты в WLD файл, пригодный для загрузки в среду разработки. Это позволило анализировать логи ошибок при декомпиляции в среде разработки.
Вторым шагом было исправление ошибок в служебных заголовках блоков, чтобы были верны маркер, номер и тип блока, описатели размеров всех секций.
Третьим шагом была коррекция блоков с таблицами типов и значениями переменных и проверка соответствий размеров блоков описателей типов переменных и блоков со значениями переменных. Также были отброшены заведомо невозможные биты из значений описателей типов и их статуса.
Четвертым шагом было исправление ошибок в таблице сегментов. После исключения заведомо невозможных значений битов. Осуществлялась проверка: сумма значений размеров сегментов + 2 = [0×22] (размер исполняемого кода).
Пятый шаг — разложение всего блока с исполняемым кодом на отдельные команды. На этом этапе потребовалась коррекция ошибок в кодах команд посредством исключения всех заведомо невозможных битов в кодах команд и их операндах, а также сопоставление команд со справочником Naumenko на предмет возможности их существования. Учитывая, что команд намного меньше, чем допускает множество от 0×0000 — 0xFFFF, то метод был достаточно эффективным.
По итогам этих мероприятий удалось убрать подавляющее большинство ошибок, но не удалось убрать все.
Так как процесс декомпиляции происходил без каких-либо сообщений об ошибках, дальнейший контроль мог быть осуществлен только с анализом логики в самом коде.
Рис. 11. Функция FC21, вызывающая поврежденный блок FB1
Для примера берем поврежденный блок FB1 и обращаем внимание, что этот функциональный блок, ответственный за процедуру управления клапанами, является универсальным куском кода, используемым для всех клапанов в конвейере. Номер клапана и сопутствующие параметры задаются в блоках с данными DBxx. Для каждого клапана выделен свой блок данных.
Анализ блоков данных, связанных с процедурой управления, позволил точно выверить ошибки в блоке описания типов переменных, так как они в точности должны были соответствовать блокам данных. Дальнейший анализ подразумевал проверку корректности операндов в инструкциях, которые по большей части являлись номерами переменных, и проверку корректности получаемых логических схем.
Рис. 12. Схема с выраженными ошибками в операндах
Результатом проведения всех видов работ стал работоспособный код, который был
успешно запущен, и конвейер возвращен к жизни.
В заключение хочется упомянуть, что это не единичное предприятие, которое
становится жертвой отказа носителя информации, вследствие того, что
обслуживающий персонал не заботился о сохранности исходного кода проекта,
который поставлялся вместе с оборудованием, а также не удосужился сделать
резервные копии MMC карты, когда она еще была исправной, что в итоге привело к серьезным убыткам на предприятии.
Хотелось бы надеяться на то, что кто-то извлечет урок из этой ситуации, и подобные отказы впредь не будут иметь столь серьезных последствий.
.
Предыдущая публикация: Хождение по рукам или грустные реалии рынка услуг восстановления данных