Как стать автором
Обновить

Необычный случай восстановления данных или немного реверс-инжиниринга PLC Siemens Simatic S7-300

Время на прочтение9 мин
Количество просмотров12K

На вопрос, какие не самые обычные случаи восстановления данных могут повстречаться в компании, профиль которой – извлекать информацию из поврежденных накопителей, можно привести пример одной из недавних задач с MMC картой из промышленного ПЛК (PLC) Siemens Simatic S7 300, в задачи которого входило управление несколькими десятками электродвигателей и клапанов, а также анализ параметров целой россыпи датчиков некоего конвейера.

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

Все началось с того, что в один из сентябрьских дней поступил звонок в офис нашей компании. Вопрос клиента состоял в том, готовы ли мы восстановить данные с MMC карты, на которой используется проприетарная файловая система.  На вопрос о том, что случилось с картой, клиент ответил, что есть несколько нечитаемых секторов. Также клиент поинтересовался, знакомы ли мы с промышленными программируемыми логическими контроллерами от Siemens, на что получил ответ, что не знакомы, но можем попытаться исследовать устройство файловой системы и масштаб проблем и далее попытаться найти способ решения.

Клиент не особо был воодушевлен этим ответом и засомневался, стоит ли везти карту памяти в наш офис для проведения аналитических мероприятий. Было предложено прислать посекторную копию для анализа и даны разъяснения как ее можно получить средствами, доступными пользователю.

Получив файл-образ флеш карты, приступаем к осмотру в шестнадцатеричном редакторе.

Рис.1. LBA 0 (MBR) из образа ММС карты
Рис.1. LBA 0 (MBR) из образа ММС карты

Первое, что бросается в глаза в начале образа – это предупреждение «Original Siemens Equipment. Use only with Siemens SIMATIC. Do not format or partition.» Не обнаружено признаков кода загрузчика, который обычно присутствует в устройствах на х86. В таблице разделов присутствуют 4 шестнадцатибайтных записи о разделах по смещениям 0x1BE, 0x1CE, 0x1DE, 0x1EE. Тип раздела 0x73 до этого случая не встречался.

При переходе по смещению на начало первого раздела, описанного в таблице, наблюдаем признаки каких-то данных, но структура и назначение неизвестны.

Рис.2. LBA 1 – начало первого раздела, описанного в таблице.
Рис.2. LBA 1 – начало первого раздела, описанного в таблице.

Также в границах раздела обнаруживается множество секторов с ненулевым заполнением и некоторым сходством по заполнению.

В границах второго и третьего разделов отсутствуют признаки данных, отличных от нуля.

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

Рис.3. LBA 31 328 – начало четвертого раздела.
Рис.3. LBA 31 328 – начало четвертого раздела.

Иных данных, отличных от нуля, на этом разделе более нет. Очевидно, что разделы 2, 3, 4 можно исключить из дальнейшего рассмотрения по причине отсутствия какого-либо значимого содержимого.

В границах первого раздела выполняем поиск каких-либо известных метаданных файловых систем средствами DataExtractorиз комплекса PC3000Express. Результаты поиска неутешительны – никаких известных структур не обнаружено.

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

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

Рис.4. PLC Siemens SIMATIC S7-300 и карта памяти MMC.
Рис.4. PLC Siemens SIMATIC S7-300 и карта памяти MMC.

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

Рис.5. Разночтения при «успешных» попытках чтения.
Рис.5. Разночтения при «успешных» попытках чтения.

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

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

В нашем случае после анализа нескольких скомпонованных вариантов становится очевидным, что данный метод без дополнительной аналитики неприменим из-за сохраняющихся разночтений в скомпонованных вариантах. На этом моменте появляется необходимость ознакомления с ПЛК Siemens Simatic S7-300.

Обращаемся к сайту производителя за документацией и обнаруживаем достаточно большой документ размером около 300 страниц, на изучение которого может потребоваться слишком много времени. Поиск альтернативных материалов привел к нахождению учебно-методического пособия «Основы языка программирования STEP7 и базового программного обеспечения промышленных контроллеров SIEMENS» Автор: Романов В.П., которое оказалось более пригодным для быстрого ознакомления с общей идеологией написания программ для контроллеров. Этого пособия и накопленных ранее знаний было достаточно, чтобы приступить к дальнейшим исследованиям.

Рис.6. Среда разработки WinSPS-S7 с открытым декомпилированным проектом.
Рис.6. Среда разработки WinSPS-S7 с открытым декомпилированным проектом.

Прикладное программное обеспечение, исполняемое в среде PLC Siemens Simatic S7 делится на блоки различного назначения:
OB – организационные блоки, которые являются обработчиками событий.
FC – функциональные блоки, которые можно вызывать с передачей параметров.
FB – функциональные блоки, отличаются от FC возможностью использовать STAT переменные.
DB – блоки данных.
SFC – системные функциональные блоки.
SFB – системные функциональные блоки.
SDB – системные блоки данных.

Рассмотрим один из блоков в виде декомпилированного кода и в откомпилированном варианте.

Рис.7. Функциональный блок FB5 в откомпилированном варианте.
Рис.7. Функциональный блок FB5 в откомпилированном варианте.

Обращаем внимание, что кроме самого кода присутствуют описатели типов переменных, а также присутствует деление кода на сегменты (networks). Это не совсем свойственно для языков, похожих на ассемблер. Это наблюдение дает нам основания полагать, что это не вольная трактовка среды разработки, а наличие служебных данных, которые описывают переменные и сегменты кода.

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

Рис.8. Откомпилированный функциональный блок FB5.
Рис.8. Откомпилированный функциональный блок FB5.

По смещению 0x24 обнаруживаем последовательность байт 0x79 0x58 0x00 0x02, где 0x79 0x58 инструкция «А», а 0x00 0x02 – её операнд. По смещению 0x9Cнаходится последовательность байт 0x65 0x00, что соответствует инструкции BE (Blockend), по достижении которой выполнение кода в блоке завершается, и возвращается управление в блок, откуда был осуществлен вызов.

Как видим, размер исполняемого кода заметно меньше, чем всего информации в блоке, и составляет 0x7A (122) байта при размере всего блока 0xFA(250) байт. Сразу бросается в глаза значение 0x00 0x7Aпо смещению 0x22, которое равно размеру исполняемого кода, и значение 0x00 0xFAпо смещению 0x0A, которое равно размеру всего блока. Проверки на других блоках подтверждают предположение о назначении этих байт. Проведя множество сравнительных и аналитических операций, выяснили назначение большинства данных, не являющихся исполняемым кодом.

Устройство блока.

Смещение

Размер

Описание

0x00

DWORD

Устойчивое выражение 0x70 0x70 0x01 0x10 – маркер начала блока

0x04

BYTE

Данное значение изменяется при перезаписи блока средствами контроллера. Возможно, счетчик. Дублируется в файловой системе.

0x05

BYTE

Тип блока (0x0С - FC, 0x0E - FB, 0x0A - DB и т.п.)

0x06

WORD

Номер блока

0x0A

WORD

Размер блока

0x10

6 BYTES

Метка времени (timestamp) – дата и время создания

0x16

6 BYTES

Метка времени (timestamp) – дата и время последних исправлений

0x1C

WORD

Размер label area (блок описания типов переменных и установленных значений)

0x1E

WORD

Размер таблицы сегментов

0x22

WORD

Размер исполняемого кода.

0x24

[0x22]

Начало исполняемого кода.

[0x22]+0x24

[0x1C]

Label Area – блок описаний типов переменных и их значений. Начало блока вычисляется посредством сложения 0x24 с значением по смещению 0x22

[0x1C]+[0x22]+0x24

[0x1E]

Таблица количества и размеров сегментов кода (Networks)

[0x1E]+[0x1C]+[0x22]+0x24

 

Информационный блок


Устройство таблицы переменных (Label Area)

Смещение

Размер

Описание

0x02

WORD

Размер описателей типов переменных

0x04

WORD

Размер блока с установленными значениями переменных

0x07

[0x02]

Блок описания типов переменных. На описание каждой переменной выделяется 2 байта. В первом байте указывается тип переменной (0x01 – bool, 0x02 – byte, 0x05 – int, 0x08 – real и т.п.). Во втором байте указывается статус переменной: не определен, определен, имеет фиксированное значение в блоке значений переменных

[0x02]+0x07

[0x04]

Блок значений переменных


Устройство таблицы сегментов кода (Networks)

Смещение

Размер

Описание

0x00

WORD

Количество сегментов кода

0x02

[0x00]*2

Записи размеров сегментов. Каждая запись состоит из двух байт. 


Устройство информационного блока

Смещение

Размер

Описание

0x00

QWORD

Текстовое поле «Author»

0x08

QWORD

Текстовое поле «Family»

0x10

QWORD

Текстовое поле «Name»

0x18

BYTE

Номер версии. Старшие 4 бита – номер перед точкой, младшие 4 бита – номер после точки


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

При осмотре данных в образе карты памяти обнаруживается, что в каждом секторе первого раздела выделяются первые 16 байт под нужды файловой системы, а 496 байт – для хранения данных. В первом секторе раздела содержатся конфигурационные параметры, один из которых является ссылкой на таблицу объектов.

Устройство служебного заголовка в секторе

Смещение

Размер

Описание

0x00

BYTE

Данное значение изменяется при перезаписи блока средствами контроллера. Возможно, счетчик. Дублируется в заголовке блока

0x01

BYTE

Тип блока

0x02

WORD

Номер блока

0x04

WORD

Порядковый номер сектора в сохраненном объекте

0x0A

WORD

Абсолютный номер следующего сектора, принадлежащего текущему объекту. 0x00 – признак последнего сектора в цепочке.

0x10

 

Пользовательские данные

Рис.9. Конфигурационный сектор
Рис.9. Конфигурационный сектор

В конфигурационном секторе по смещению 0x2A находится абсолютный указатель на начало таблицы размещения объектов (получаемое смещение в байтах 0x0152*0x0200=0x2A400).

Рис.10.Таблица размещения объектов
Рис.10.Таблица размещения объектов

По рисунку 10 достаточно легко заметить, что размер одной записи в таблице составляет 16 байт.

Устройство записи в таблице размещения объектов.

Смещение

Размер

Описание

0x01

BYTE

Тип блока

0x02

WORD

Номер блока

0x06

WORD

Размер данных блока (дублируется в заголовке блока)

0X0A

WORD

Абсолютный номер первого сектора блока

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

Первым шагом было приведение в порядок всех секторных заголовков в поврежденных местах, чтобы начала отрабатывать процедура конвертации из образа MMC карты в WLD файл, пригодный для загрузки в среду разработки. Это позволило анализировать логи ошибок при декомпиляции в среде разработки.

Вторым шагом было исправление ошибок в служебных заголовках блоков, чтобы были верны маркер, номер и тип блока, описатели размеров всех секций.

Третьим шагом была коррекция блоков с таблицами типов и значениями переменных и проверка соответствий размеров блоков описателей типов переменных и блоков со значениями переменных. Также были отброшены заведомо невозможные биты из значений описателей типов и их статуса.

Четвертым шагом было исправление ошибок в таблице сегментов. После исключения заведомо невозможных значений битов. Осуществлялась проверка: сумма значений размеров сегментов + 2 = [0x22] (размер исполняемого кода).

Пятый шаг – разложение всего блока с исполняемым кодом на отдельные команды. На этом этапе потребовалась коррекция ошибок в кодах команд посредством исключения всех заведомо невозможных битов в кодах команд и их операндах, а также сопоставление команд со справочником Naumenko на предмет возможности их существования. Учитывая, что команд намного меньше, чем допускает множество от 0x0000 – 0xFFFF, то метод был достаточно эффективным.

По итогам этих мероприятий удалось убрать подавляющее большинство ошибок, но не удалось убрать все.

Так как процесс декомпиляции происходил без каких-либо сообщений об ошибках, дальнейший контроль мог быть осуществлен только с анализом логики в самом коде.

Рис.11. Функция FC21, вызывающая поврежденный блок FB1
Рис.11. Функция FC21, вызывающая поврежденный блок FB1

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

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

Рис.12. Схема с выраженными ошибками в операндах
Рис.12. Схема с выраженными ошибками в операндах

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

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

Хотелось бы надеяться на то, что кто-то извлечет урок из этой ситуации, и подобные отказы впредь не будут иметь столь серьезных последствий.

Предыдущая публикация: Хождение по рукам или грустные реалии рынка услуг восстановления данных

Теги:
Хабы:
Всего голосов 36: ↑36 и ↓0+36
Комментарии37

Публикации

Истории

Работа

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань