Акыркы PHDays 9да биз газ соргуч заводду бузуп алуу боюнча сынак өткөрдүк . Сайтта бир эле өнөр жай процессин туураган ар кандай коопсуздук параметрлери (Коопсуздук жок, Төмөн коопсуздук, Жогорку коопсуздук) болгон үч стенд бар болчу: басым астында аба шарга айдалып (андан кийин бошотулган).
Ар кандай коопсуздук параметрлерине карабастан, стенддердин аппараттык курамы бирдей болгон: Siemens Simatic PLC S7-300 сериясы; авариялык дефляция баскычы жана басымды өлчөөчү аспап (PLC санарип киргизүүлөрүнө (DI) туташтырылган); абанын инфляциясы жана дефляциясы үчүн иштеген клапандар (PLC (DO) санарип чыгууларына туташтырылган) - төмөнкү сүрөттү караңыз.

PLC басымдын көрсөткүчтөрүнө жараша жана анын программасына ылайык, шарды өчүрүү же толтуруу чечимин кабыл алды (тиешелүү клапандарды ачып, жапты). Бирок бардык стенддерде кол менен башкаруу режими болгон, бул клапандардын абалын эч кандай чектөөсүз башкарууга мүмкүндүк берген.
Стенддер бул режимди иштетүүнүн татаалдыгы менен айырмаланган: корголбогон стендде муну жасоо эң оңой, ал эми Жогорку коопсуздук стендинде тиешелүүлүгүнө жараша кыйыныраак болгон.
Алты маселенин бешөө эки күндө чечилди; Биринчи орунду ээлеген катышуучу 233 упайга ээ болду (ал сынакка бир жума даярданган). Үч жеңүүчү: I орун – а1ексданды, II – Рубикоид, III – Зе.
Бирок, PHDays учурунда катышуучулардын бири дагы үч стендди жеңе алган жок, ошондуктан биз онлайн сынак өткөрүүнү чечтик жана июнь айынын башында эң татаал тапшырманы жарыяладык. Катышуучулар тапшырманы бир айдын ичинде бүтүрүп, туу таап, чечүү жолун кеңири жана кызыктуу баяндап бериши керек болчу.
Кесиптин ылдый жагында биз бир айдын ичинде жөнөтүлгөн тапшырманын эң жакшы чечиминин анализин жарыялайбыз, аны PHDays учурунда сынакта 1-орунду алган Digital Security компаниясынан Алексей Коврижных (aXNUMXexdandy) тапты. Төмөндө анын текстин комментарийлерибиз менен сунуштайбыз.
Баштапкы анализ
Ошентип, тапшырма төмөнкү файлдар менен архивди камтыйт:
- block_upload_traffic.pcapng
- DB100.bin
- hints.txt
hints.txt файлы тапшырманы чечүү үчүн керектүү маалыматты жана кеңештерди камтыйт. Бул жерде анын мазмуну:
- Петрович кечээ мага блокторду PlcSimден Step7ге жүктөй аласың деп айтты.
- Стендде Siemens Simatic S7-300 series PLC колдонулган.
- PlcSim бул Siemens S7 PLC үчүн программаларды иштетүүгө жана мүчүлүштүктөрдү оңдоого мүмкүндүк берген PLC эмулятору.
DB100.bin файлында DB100 PLC маалымат блогу бар окшойт: 00000000: 0100 0102 6e02 0401 0206 0100 0101 0102 ....n......... 00000010: 1002 0501 0202 2002 . ..... ......... 0501: 0206 0100 0102 00000020 0102 7702 0401 0206a0100 ..w............. 0103: 0102 0 02 00000030 0501 0202 ................ 1602: 0501 0206 0100 0104 0102 00000040 7502a0401 0206 u............... 0100: 0105 0102 0 02 0501 00000050 0202 1602............0501. 0206: 0100 0106 0102 3402 4 00000060 0401 0206 .........&..... 0100: 0107c0102 2602 0501 0202 00000070 4 ...... 02.... : 0501 0206 0100 0108 0102a3302 0401 3 00000080 ................ 0206: 0100 0109 0102 0a 02 0501 0202 1602 .........00000090. 0501a0206: 0100 010b 0102 3702 0401 0206 7 000000 ......".....F... 0b0100: 010 0102 2202c 0501 0202 4602 .......0501 .. 000000c0: 0206d 0100 010a0102 3302 0401 0206 0100 3 ................ 000000d0: 010 0102e 0 02d0501 0202 1602........ .... 0501e0206: 000000 0 0100 010 0102 6 02 0401 ......#...... 0206f0100: 010 000000 0 0102 1102 0501....... ..... 0202: 2302 0501 0206 0100 000000 0 0110 0102 ......%....... 3502: 0401 0206 0100 0111 0102 5.....00000100 .....&. 1202: 0501 0202 2502c0501 0206 0100 0112 ....L......
Аты айтып тургандай, block_upload_traffic.pcapng файлы PLCге блоктук жүктөө трафиктин таштандысын камтыйт.
Белгилей кетсек, конференциянын жүрүшүндө мелдеш өтүүчү жердеги бул трафикти алуу бир аз кыйыныраак болгон. Бул үчүн, TeslaSCADA2 үчүн долбоордун файлынан сценарийди түшүнүү керек болчу. Андан RC4 аркылуу шифрленген таштанды кайда жайгашканын жана аны чечмелөө үчүн кандай ачкыч колдонуу керектигин түшүнүүгө мүмкүн болду. Сайттагы маалымат блокторунун таштандыларын S7 протоколунун кардары аркылуу алууга болот. Бул үчүн мен Snap7 пакетинен демо кардарды колдондум.
Трафик таштандысынан сигналды иштетүү блокторун алуу
Таштандынын мазмунуна карап, анда OB1, FC1, FC2 жана FC3 сигналдарды иштетүү блоктору бар экенин түшүнүүгө болот:

Бул блокторду алып салуу керек. Муну, мисалы, трафикти pcapng форматынан pcap форматына өзгөртүп, төмөнкү скрипт менен жасоого болот:
#!/usr/bin/env python2
import struct
from scapy.all import *
packets = rdpcap('block_upload_traffic.pcap')
s7_hdr_struct = '>BBHHHHBB'
s7_hdr_sz = struct.calcsize(s7_hdr_struct)
tpkt_cotp_sz = 7
names = iter(['OB1.bin', 'FC1.bin', 'FC2.bin', 'FC3.bin'])
buf = ''
for packet in packets:
if packet.getlayer(IP).src == '10.0.102.11':
tpkt_cotp_s7 = str(packet.getlayer(TCP).payload)
if len(tpkt_cotp_s7) < tpkt_cotp_sz + s7_hdr_sz:
continue
s7 = tpkt_cotp_s7[tpkt_cotp_sz:]
s7_hdr = s7[:s7_hdr_sz]
param_sz = struct.unpack(s7_hdr_struct, s7_hdr)[4]
s7_param = s7[12:12+param_sz]
s7_data = s7[12+param_sz:]
if s7_param in ('x1ex00', 'x1ex01'): # upload
buf += s7_data[4:]
elif s7_param == 'x1f':
with open(next(names), 'wb') as f:
f.write(buf)
buf = ''Алынган блокторду карап чыгып, алар ар дайым 70 70 байт (бб) менен башталарын байкайсыз. Эми аларды анализдегенди үйрөнүш керек. Тапшырма кыйытмасы бул үчүн PlcSim колдонуу керек экенин көрсөтүп турат.
Блоктардан адам окуй турган нускамаларды алуу
Биринчиден, келгиле, S7-PlcSim программасын Simatic Manager программасынын жардамы менен ага кайталануучу инструкциялары бар бир нече блокторду (= Q 0.0) жүктөө жана эмулятордо алынган PLCти example.plc файлына сактоо менен программалаганга аракет кылалы. Файлдын мазмунун карап, сиз жүктөгөн блоктордун башталышын биз мурда тапкан 70 70 кол тамгасы менен оңой аныктай аласыз. Блоктордун алдында, сыягы, блоктун көлөмү 4-байт аз-эндиан мааниси катары жазылган.

PLC файлдарынын түзүмү жөнүндө маалымат алгандан кийин, PLC S7 программаларын окуу үчүн төмөнкү иш-аракеттер планы пайда болду:
- Simatic Менеджерди колдонуп, биз S7-PlcSimде таштандыдан алганга окшош блок структурасын түзөбүз. Блоктун өлчөмдөрү дал келиши керек (бул блокторду керектүү сандагы нускамалар менен толтуруу менен жетишилет) жана алардын идентификаторлору (OB1, FC1, FC2, FC3).
- PLCти файлга сактаңыз.
- Биз пайда болгон файлдагы блоктордун мазмунун трафик таштандысынан алынган блокторго алмаштырабыз. Блоктордун башталышы кол менен аныкталат.
- Алынган файлды S7-PlcSimге жүктөйбүз жана Simatic Managerдеги блоктордун мазмунун карайбыз.
Блокторду, мисалы, төмөнкү код менен алмаштырууга болот:
with open('original.plc', 'rb') as f:
plc = f.read()
blocks = []
for fname in ['OB1.bin', 'FC1.bin', 'FC2.bin', 'FC3.bin']:
with open(fname, 'rb') as f:
blocks.append(f.read())
i = plc.find(b'pp')
for block in blocks:
plc = plc[:i] + block + plc[i+len(block):]
i = plc.find(b'pp', i + 1)
with open('target.plc', 'wb') as f:
f.write(plc)Алексей балким кыйыныраак, бирок дагы эле туура жолду тандады. Биз катышуучулар NetToPlcSim программасын колдонуп, PlcSim тармак аркылуу байланышып, блокторду Snap7 аркылуу PlcSimге жүктөй алышат жана андан кийин бул блокторду PlcSimден долбоор катары иштеп чыгуу чөйрөсүн колдонуп жүктөй алышат деп ойлогонбуз.
S7-PlcSimде пайда болгон файлды ачуу менен, сиз Simatic Manager аркылуу кайра жазылган блокторду окуй аласыз. Түзмөктү башкаруунун негизги функциялары FC1 блогунда жазылган. Өзгөчө белгилей кетчү нерсе, #TEMP0 өзгөрмөсү, күйгүзүлгөндө PLC башкаруусун M2.2 жана M2.3 бит эс тутумунун маанилеринин негизинде кол режимине койгондой көрүнөт. #TEMP0 мааниси FC3 функциясы тарабынан коюлган.

Маселени чечүү үчүн, сиз FC3 функциясын талдап, логикалык функцияны кайтарышы үчүн эмне кылуу керектигин түшүнүшүңүз керек.
Мелдеш сайтындагы Low Security стендиндеги PLC сигналын иштетүү блоктору ушундай эле жол менен жайгаштырылган, бирок #TEMP0 өзгөрмөнүн маанисин коюу үчүн DB1 блогуна менин ниндзя жолумду жазуу жетиштүү болду. Блоктогу маанини текшерүү оңой эле жана блоктук программалоо тилин терең билүүнү талап кылбайт. Албетте, High Security деңгээлинде кол менен башкарууга жетишүү алда канча кыйын болот жана STL тилинин татаалдыктарын түшүнүү керек (S7 PLC программалоонун жолдорунун бири).
FC3 тескери блок
STL көрсөтүүсүндө FC3 блогунун мазмуну:
L B#16#0
T #TEMP13
T #TEMP15
L P#DBX 0.0
T #TEMP4
CLR
= #TEMP14
M015: L #TEMP4
LAR1
OPN DB 100
L DBLG
TAR1
<=D
JC M016
L DW#16#0
T #TEMP0
L #TEMP6
L W#16#0
<>I
JC M00d
L P#DBX 0.0
LAR1
M00d: L B [AR1,P#0.0]
T #TEMP5
L W#16#1
==I
JC M007
L #TEMP5
L W#16#2
==I
JC M008
L #TEMP5
L W#16#3
==I
JC M00f
L #TEMP5
L W#16#4
==I
JC M00e
L #TEMP5
L W#16#5
==I
JC M011
L #TEMP5
L W#16#6
==I
JC M012
JU M010
M007: +AR1 P#1.0
L P#DBX 0.0
LAR2
L B [AR1,P#0.0]
L C#8
*I
+AR2
+AR1 P#1.0
L B [AR1,P#0.0]
JL M003
JU M001
JU M002
JU M004
M003: JU M005
M001: OPN DB 101
L B [AR2,P#0.0]
T #TEMP0
JU M006
M002: OPN DB 101
L B [AR2,P#0.0]
T #TEMP1
JU M006
M004: OPN DB 101
L B [AR2,P#0.0]
T #TEMP2
JU M006
M00f: +AR1 P#1.0
L B [AR1,P#0.0]
L C#8
*I
T #TEMP11
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9
TAR1 #TEMP4
OPN DB 101
L P#DBX 0.0
LAR1
L #TEMP11
+AR1
LAR2 #TEMP9
L B [AR2,P#0.0]
T B [AR1,P#0.0]
L #TEMP4
LAR1
JU M006
M008: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP3
+AR1 P#1.0
L B [AR1,P#0.0]
JL M009
JU M00b
JU M00a
JU M00c
M009: JU M005
M00b: L #TEMP3
T #TEMP0
JU M006
M00a: L #TEMP3
T #TEMP1
JU M006
M00c: L #TEMP3
T #TEMP2
JU M006
M00e: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10
TAR1 #TEMP4
LAR1 #TEMP9
LAR2 #TEMP10
L B [AR1,P#0.0]
L B [AR2,P#0.0]
AW
INVI
T #TEMP12
L B [AR1,P#0.0]
L B [AR2,P#0.0]
OW
L #TEMP12
AW
T B [AR1,P#0.0]
L DW#16#0
T #TEMP0
L MB 101
T #TEMP1
L MB 102
T #TEMP2
L #TEMP4
LAR1
JU M006
M011: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10
TAR1 #TEMP4
LAR1 #TEMP9
LAR2 #TEMP10
L B [AR1,P#0.0]
L B [AR2,P#0.0]
-I
T B [AR1,P#0.0]
L DW#16#0
T #TEMP0
L MB 101
T #TEMP1
L MB 102
T #TEMP2
L #TEMP4
LAR1
JU M006
M012: L #TEMP15
INC 1
T #TEMP15
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10
TAR1 #TEMP4
LAR1 #TEMP9
LAR2 #TEMP10
L B [AR1,P#0.0]
L B [AR2,P#0.0]
==I
JCN M013
JU M014
M013: L P#DBX 0.0
LAR1
T #TEMP4
L B#16#0
T #TEMP6
JU M006
M014: L #TEMP4
LAR1
L #TEMP13
L L#1
+I
T #TEMP13
JU M006
M006: L #TEMP0
T MB 100
L #TEMP1
T MB 101
L #TEMP2
T MB 102
+AR1 P#1.0
L #TEMP6
+ 1
T #TEMP6
JU M005
M010: L P#DBX 0.0
LAR1
L 0
T #TEMP6
TAR1 #TEMP4
M005: TAR1 #TEMP4
CLR
= #TEMP16
L #TEMP13
L L#20
==I
S #TEMP16
L #TEMP15
==I
A #TEMP16
JC M017
L #TEMP13
L L#20
<I
S #TEMP16
L #TEMP15
==I
A #TEMP16
JC M018
JU M019
M017: SET
= #TEMP14
JU M016
M018: CLR
= #TEMP14
JU M016
M019: CLR
O #TEMP14
= #RET_VAL
JU M015
M016: CLR
O #TEMP14
= #RET_VALКод абдан узун жана STL менен тааныш эмес бирөө үчүн татаал сезилиши мүмкүн. Бул макаланын алкагында ар бир нускаманы талдап чыгуунун эч кандай мааниси жок. . Бул жерде мен иштеп чыккандан кийин ошол эле кодду көрсөтөм - энбелгилердин жана өзгөрмөлөрдүн атын өзгөртүү жана операция алгоритмин жана STL тилинин кээ бир конструкцияларын сүрөттөгөн комментарийлерди кошуу. Каралып жаткан блок DB100 блогунда жайгашкан кээ бир байт-кодду аткарган виртуалдык машинаны камтыганын дароо белгилеп кетейин, анын мазмуну биз билебиз. Виртуалдык машина инструкциялары 1 байт операциялык коддон жана аргументтердин байттарынан турат, ар бир аргумент үчүн бир байт. Бардык каралып жаткан инструкцияларда эки аргумент бар, мен алардын маанилерин X жана Y деп атадым.
Код иштетилгенден кийин]
# Инициализация различных переменных
L B#16#0
T #CHECK_N # Счетчик успешно пройденных проверок
T #COUNTER_N # Счетчик общего количества проверок
L P#DBX 0.0
T #POINTER # Указатель на текущую инструкцию
CLR
= #PRE_RET_VAL
# Основной цикл работы интерпретатора байт-кода
LOOP: L #POINTER
LAR1
OPN DB 100
L DBLG
TAR1
<=D # Проверка выхода указателя за пределы программы
JC FINISH
L DW#16#0
T #REG0
L #TEMP6
L W#16#0
<>I
JC M00d
L P#DBX 0.0
LAR1
# Конструкция switch - case для обработки различных опкодов
M00d: L B [AR1,P#0.0]
T #OPCODE
L W#16#1
==I
JC OPCODE_1
L #OPCODE
L W#16#2
==I
JC OPCODE_2
L #OPCODE
L W#16#3
==I
JC OPCODE_3
L #OPCODE
L W#16#4
==I
JC OPCODE_4
L #OPCODE
L W#16#5
==I
JC OPCODE_5
L #OPCODE
L W#16#6
==I
JC OPCODE_6
JU OPCODE_OTHER
# Обработчик опкода 01: загрузка значения из DB101[X] в регистр Y
# OP01(X, Y): REG[Y] = DB101[X]
OPCODE_1: +AR1 P#1.0
L P#DBX 0.0
LAR2
L B [AR1,P#0.0] # Загрузка аргумента X (индекс в DB101)
L C#8
*I
+AR2
+AR1 P#1.0
L B [AR1,P#0.0] # Загрузка аргумента Y (индекс регистра)
JL M003 # Аналог switch - case на основе значения Y
JU M001 # для выбора необходимого регистра для записи.
JU M002 # Подобные конструкции используются и в других
JU M004 # операциях ниже для аналогичных целей
M003: JU LOOPEND
M001: OPN DB 101
L B [AR2,P#0.0]
T #REG0 # Запись значения DB101[X] в REG[0]
JU PRE_LOOPEND
M002: OPN DB 101
L B [AR2,P#0.0]
T #REG1 # Запись значения DB101[X] в REG[1]
JU PRE_LOOPEND
M004: OPN DB 101
L B [AR2,P#0.0]
T #REG2 # Запись значения DB101[X] в REG[2]
JU PRE_LOOPEND
# Обработчик опкода 02: загрузка значения X в регистр Y
# OP02(X, Y): REG[Y] = X
OPCODE_2: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP3
+AR1 P#1.0
L B [AR1,P#0.0]
JL M009
JU M00b
JU M00a
JU M00c
M009: JU LOOPEND
M00b: L #TEMP3
T #REG0
JU PRE_LOOPEND
M00a: L #TEMP3
T #REG1
JU PRE_LOOPEND
M00c: L #TEMP3
T #REG2
JU PRE_LOOPEND
# Опкод 03 не используется в программе, поэтому пропустим его
...
# Обработчик опкода 04: сравнение регистров X и Y
# OP04(X, Y): REG[0] = 0; REG[X] = (REG[X] == REG[Y])
OPCODE_4: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7 # первый аргумент - X
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9 # REG[X]
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10 # REG[Y]
TAR1 #POINTER
LAR1 #TEMP9 # REG[X]
LAR2 #TEMP10 # REG[Y]
L B [AR1,P#0.0]
L B [AR2,P#0.0]
AW
INVI
T #TEMP12 # ~(REG[Y] & REG[X])
L B [AR1,P#0.0]
L B [AR2,P#0.0]
OW
L #TEMP12
AW # (~(REG[Y] & REG[X])) & (REG[Y] | REG[X]) - аналог проверки на равенство
T B [AR1,P#0.0]
L DW#16#0
T #REG0
L MB 101
T #REG1
L MB 102
T #REG2
L #POINTER
LAR1
JU PRE_LOOPEND
# Обработчик опкода 05: вычитание регистра Y из X
# OP05(X, Y): REG[0] = 0; REG[X] = REG[X] - REG[Y]
OPCODE_5: +AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9 # REG[X]
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10 # REG[Y]
TAR1 #POINTER
LAR1 #TEMP9
LAR2 #TEMP10
L B [AR1,P#0.0]
L B [AR2,P#0.0]
-I # ACCU1 = ACCU2 - ACCU1, REG[X] - REG[Y]
T B [AR1,P#0.0]
L DW#16#0
T #REG0
L MB 101
T #REG1
L MB 102
T #REG2
L #POINTER
LAR1
JU PRE_LOOPEND
# Обработчик опкода 06: инкремент #CHECK_N при равенстве регистров X и Y
# OP06(X, Y): #CHECK_N += (1 if REG[X] == REG[Y] else 0)
OPCODE_6: L #COUNTER_N
INC 1
T #COUNTER_N
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP7 # REG[X]
L P#M 100.0
LAR2
L #TEMP7
L C#8
*I
+AR2
TAR2 #TEMP9 # REG[X]
+AR1 P#1.0
L B [AR1,P#0.0]
T #TEMP8
L P#M 100.0
LAR2
L #TEMP8
L C#8
*I
+AR2
TAR2 #TEMP10 # REG[Y]
TAR1 #POINTER
LAR1 #TEMP9 # REG[Y]
LAR2 #TEMP10 # REG[X]
L B [AR1,P#0.0]
L B [AR2,P#0.0]
==I
JCN M013
JU M014
M013: L P#DBX 0.0
LAR1
T #POINTER
L B#16#0
T #TEMP6
JU PRE_LOOPEND
M014: L #POINTER
LAR1
# Инкремент значения #CHECK_N
L #CHECK_N
L L#1
+I
T #CHECK_N
JU PRE_LOOPEND
PRE_LOOPEND: L #REG0
T MB 100
L #REG1
T MB 101
L #REG2
T MB 102
+AR1 P#1.0
L #TEMP6
+ 1
T #TEMP6
JU LOOPEND
OPCODE_OTHER: L P#DBX 0.0
LAR1
L 0
T #TEMP6
TAR1 #POINTER
LOOPEND: TAR1 #POINTER
CLR
= #TEMP16
L #CHECK_N
L L#20
==I
S #TEMP16
L #COUNTER_N
==I
A #TEMP16
# Все проверки пройдены, если #CHECK_N == #COUNTER_N == 20
JC GOOD
L #CHECK_N
L L#20
<I
S #TEMP16
L #COUNTER_N
==I
A #TEMP16
JC FAIL
JU M019
GOOD: SET
= #PRE_RET_VAL
JU FINISH
FAIL: CLR
= #PRE_RET_VAL
JU FINISH
M019: CLR
O #PRE_RET_VAL
= #RET_VAL
JU LOOP
FINISH: CLR
O #PRE_RET_VAL
= #RET_VALВиртуалдык машинанын инструкциялары жөнүндө түшүнүк алгандан кийин, DB100 блогундагы байт кодду талдоо үчүн кичинекей дезасемблер жазалы:
import string
alph = string.ascii_letters + string.digits
with open('DB100.bin', 'rb') as f:
m = f.read()
pc = 0
while pc < len(m):
op = m[pc]
if op == 1:
print('R{} = DB101[{}]'.format(m[pc + 2], m[pc + 1]))
pc += 3
elif op == 2:
c = chr(m[pc + 1])
c = c if c in alph else '?'
print('R{} = {:02x} ({})'.format(m[pc + 2], m[pc + 1], c))
pc += 3
elif op == 4:
print('R0 = 0; R{} = (R{} == R{})'.format(
m[pc + 1], m[pc + 1], m[pc + 2]))
pc += 3
elif op == 5:
print('R0 = 0; R{} = R{} - R{}'.format(
m[pc + 1], m[pc + 1], m[pc + 2]))
pc += 3
elif op == 6:
print('CHECK (R{} == R{})n'.format(
m[pc + 1], m[pc + 2]))
pc += 3
else:
print('unk opcode {}'.format(op))
breakНатыйжада, биз төмөнкү виртуалдык машина кодун алабыз:
Виртуалдык машина коду
R1 = DB101[0]
R2 = 6e (n)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[1]
R2 = 10 (?)
R0 = 0; R1 = R1 - R2
R2 = 20 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[2]
R2 = 77 (w)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[3]
R2 = 0a (?)
R0 = 0; R1 = R1 - R2
R2 = 16 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[4]
R2 = 75 (u)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[5]
R2 = 0a (?)
R0 = 0; R1 = R1 - R2
R2 = 16 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[6]
R2 = 34 (4)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[7]
R2 = 26 (?)
R0 = 0; R1 = R1 - R2
R2 = 4c (L)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[8]
R2 = 33 (3)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[9]
R2 = 0a (?)
R0 = 0; R1 = R1 - R2
R2 = 16 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[10]
R2 = 37 (7)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[11]
R2 = 22 (?)
R0 = 0; R1 = R1 - R2
R2 = 46 (F)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[12]
R2 = 33 (3)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[13]
R2 = 0a (?)
R0 = 0; R1 = R1 - R2
R2 = 16 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[14]
R2 = 6d (m)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[15]
R2 = 11 (?)
R0 = 0; R1 = R1 - R2
R2 = 23 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[16]
R2 = 35 (5)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[17]
R2 = 12 (?)
R0 = 0; R1 = R1 - R2
R2 = 25 (?)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)
R1 = DB101[18]
R2 = 33 (3)
R0 = 0; R1 = (R1 == R2)
CHECK (R1 == R0)
R1 = DB101[19]
R2 = 26 (?)
R0 = 0; R1 = R1 - R2
R2 = 4c (L)
R0 = 0; R1 = R1 - R2
CHECK (R1 == R0)Көрүнүп тургандай, бул программа жөн гана DB101ден ар бир белгинин белгилүү бир мааниге барабар экендигин текшерет. Бардык текшерүүлөрдү өткөрүү үчүн акыркы сап: n0w u 4r3 7h3 m4573r. Эгерде бул линия DB101 блогуна жайгаштырылса, анда кол менен PLC башкаруусу иштетилип, шарды жардырып же өчүрүү мүмкүн болот.
Баары болду! Алексей индустриалдык ниндзяга татыктуу жогорку билимин көрсөттү :) Жеңүүчүгө эсте каларлык сыйлыктарды жөнөттүк. Бардык катышуучуларга чоң рахмат!
Source: www.habr.com
