Di PHDdayên paşîn 9 de me pêşbaziyek ji bo hakkirina kargehek pompkirina gazê li dar xist - pêşbazî . Li ser malperê sê stûnên bi pîvanên ewlehiyê yên cihêreng (Bê Ewlehî, Ewlekariya Kêm, Ewlekariya Bilind) hebûn, ku heman pêvajoya pîşesaziyê dişibînin: hewaya di bin zextê de di nav balonekê de hate kişandin (û dûv re hate berdan).
Tevî pîvanên ewlehiyê yên cihêreng, pêkhateya hardware ya standan yek bû: Siemens Simatic PLC S7-300 series; Bişkojka deflasyona acîl û cîhaza pîvana zextê (bi têketinên dîjîtal ên PLC (DI) ve girêdayî ye); valves ku ji bo enflasyon û deflasyona hewayê dixebitin (girêdayî derketinên dîjîtal ên PLC (DO)) - li jimareya jêrîn binêrin.

PLC, li gorî xwendinên zextê û li gorî bernameya xwe, biryar da ku topê bişewitîne an bifroşe (valên têkildar vekirin û girtin). Lêbelê, hemî standan xwedan modek kontrolê ya destan bûn, ku îmkana kontrolkirina rewşên valves bêyî ti sînordar dikir.
Stand di tevliheviya çalakkirina vê modê de ji hev cûda bûn: li rawestgeha bêparastin kirina vê yekê herî hêsan bû, û li rawestgeha Ewlekariya Bilind jî bi vî rengî dijwartir bû.
Di nava du rojan de ji şeş pirsgirêkan 233 kes hatin çareserkirin; Beşdarê yekem 1 pûan bi dest xist (wî hefteyek xwe ji bo pêşbirkê amade kir). Sê serketî: Ez cîh - aXNUMXexdandy, II - Rubikoid, III - Ze.
Lêbelê, di dema PHDays de, yek ji beşdaran nekarî her sê standan bi ser bikeve, ji ber vê yekê me biryar da ku em pêşbaziyek serhêl çêbikin û di destpêka hezîranê de karê herî dijwar weşandin. Diviyabû ku beşdaran di nava mehekê de peywirê biqedînin, alê bibînin û çareseriyê bi berfirehî û bi awayekî balkêş vebêjin.
Li jêr qutkirinê em analîzek çareseriya çêtirîn a peywirê ji yên ku di mehê de hatine şandin diweşînin, ew ji hêla Alexey Kovrizhnykh (a1exdandy) ji pargîdaniya Ewlekariya Dîjîtal ve, ku di pêşbaziyê de di dema PHDays de cîhê XNUMX-emîn girt, hate dîtin. Li jêr em nivîsa wê bi şîroveyên xwe pêşkêş dikin.
Analîza destpêkê
Ji ber vê yekê, peywirê arşîvek bi pelên jêrîn vekir:
- block_upload_traffic.pcapng
- DB100.bin
- hints.txt
Di pelê hints.txt de agahdarî û şîretên pêwîst ji bo çareser kirina peywirê heye. Li vir naveroka wê hene:
- Petrovich duh ji min re got ku hûn dikarin blokan ji PlcSim li Step7 bar bikin.
- Siemens Simatic S7-300 series PLC li standê hate bikar anîn.
- PlcSim emûlatorek PLC ye ku dihêle hûn ji bo PLCyên Siemens S7 bernameyan bimeşînin û debug bikin.
Di pelê DB100.bin de bloka daneya DB100 PLC dixuye: 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 00000040a7502 0401 u................ 0206 0100..........0105. 0102: 0 02 0501 00000050 0202 1602 0501 0206 .........&..... 0100: 0106c0102 3402 4 00000060 0401 0206 0100 ....... : 0107 0102 2602 0501 0202a00000070 4 02 0501 ................ 0206: 0100 0108 0102 3302a 0401 3 00000080 0206 .........0100. 0109a0102: 0 02b 0501 0202 1602 00000090 0501 0206 ......".....F... 0100b010: 0102 3702 0401c 0206 7 000000 .....0 ... .. 0100c010: 0102d 2202 0501a0202 4602 0501 000000 0 0206 ................ 0100d010: 0102 3302e 0401 0206d0100 3 000000 . .... 0e010: 0102 0 02 0501 0202 1602 0501 0206 ........#...... 000000f0: 0100 010 0102 6 02 0401 . ..... 0206: 0100 010 000000 0 0102 1102 0501 0202 ......%......... 2302: 0501 0206 0100 000000 0 0110 . ....& 0102: 3502 0401 0206c0100 0111 0102 5 ....L......
Wekî ku ji navê xwe diyar dike, pelê block_upload_traffic.pcapng di nav PLC-ê de seyrûsefera barkirina blokê dihewîne.
Hêjayî gotinê ye ku ev barkirina seyrûsefera li cîhê pêşbaziyê di dema konferansê de hinekî dijwartir bû. Ji bo vê yekê, pêdivî bû ku ji pelê projeyê ji bo TeslaSCADA2 skrîptê fam bikin. Ji wê re gengaz bû ku meriv fêm bike ka çolê ku bi karanîna RC4 hatî şîfrekirin li ku derê ye û kîjan mifteyê hewce dike ku were bikar anîn da ku wê deşîfre bike. Dorpêçên blokên daneyê yên li ser malperê dikarin bi karanîna muwekîlê protokola S7 ve werin bidestxistin. Ji bo vê yekê min muwekîlê demo ji pakêta Snap7 bikar anî.
Derxistina blokên hilberandina sînyalê ji topa trafîkê
Li naveroka avêtinê mêze dikin, hûn dikarin fêm bikin ku ew blokên hilberandina nîşanê OB1, FC1, FC2 û FC3 dihewîne:

Divê ev blokan bên rakirin. Ev dikare, wek nimûne, bi skrîpta jêrîn were kirin, ku berê seyrûsefera ji formata pcapng veguhezandiye 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 = ''Dema ku hûn blokên encam lêkolîn bikin, hûn ê bibînin ku ew her gav bi bytes 70 70 (pp) dest pê dikin. Naha hûn hewce ne ku fêr bibin ka meriv çawa wan analîz dike. Pêşniyara peywirê pêşniyar dike ku hûn hewce ne ku ji bo vê yekê PlcSim bikar bînin.
Ji blokan rêwerzên ku ji hêla mirovan ve têne xwendin
Pêşîn, em hewl bidin ku S7-PlcSim bername bikin û bi rêwerzên dubare (= Q 0.0) tê de bi karanîna nermalava Rêvebirê Simatic ve gelek blokan bar bikin, û PLC-ya ku di emulatorê de hatî wergirtin di pelê example.plc de hilînin. Bi dîtina naveroka pelê, hûn dikarin bi hêsanî destpêka blokên dakêşandî bi îmzeya 70 70, ya ku me berê keşif kiribû, diyar bikin. Beriya blokan, xuya ye, mezinahiya blokê wekî nirxek hindik-endî ya 4-byte tê nivîsandin.

Piştî ku me di derheqê strukturên pelên plc de agahdarî wergirt, ji bo xwendina bernameyên PLC S7 pilana çalakiyê ya jêrîn xuya bû:
- Bi karanîna Rêvebirê Simatic, em di S7-PlcSim de avahiyek blokek mîna ya ku me ji avêtinê wergirtiye diafirîne. Pêdivî ye ku mezinahiya blokan li hev bikin (ev bi dagirtina blokan bi hêjmara rêwerzên pêwîst re tê bidestxistin) û nasnameyên wan (OB1, FC1, FC2, FC3).
- PLC li pelek hilînin.
- Em naveroka blokan di pelê encam de bi blokên ji çolê trafîkê veguherînin. Destpêka blokan bi îmzeyê tê destnîşankirin.
- Em pelê encam li S7-PlcSim bar dikin û li naveroka blokan di Gerînendeyê Simatic de dinêrin.
Blok dikarin werin guheztin, mînakî, bi koda jêrîn:
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)Alexey rêyek belkî dijwartir, lê dîsa jî rast girt. Me texmîn kir ku beşdar dê bernameya NetToPlcSim bikar bînin da ku PlcSim bikaribe li ser torê têkiliyê deyne, blokan bi riya Snap7-ê li PlcSim bar bike, û dûv re van blokan wekî projeyek ji PlcSim bi karanîna hawîrdora pêşkeftinê dakêşîne.
Bi vekirina pelê encam di S7-PlcSim de, hûn dikarin bi karanîna Rêvebirê Simatic blokên hatî nivîsandin bixwînin. Fonksiyonên sereke yên kontrolkirina cîhazê di bloka FC1 de têne tomar kirin. Têbînî bi taybetî guhêrbar #TEMP0 ye, ku gava tê vemirandin xuya dike ku kontrola PLC-ê li ser bingeha nirxên bîranîna bit M2.2 û M2.3-ê li ser moda destan saz dike. Nirxa #TEMP0 ji hêla fonksiyona FC3 ve hatî danîn.

Ji bo çareserkirina pirsgirêkê, hûn hewce ne ku fonksiyona FC3 analîz bikin û fêm bikin ka çi divê were kirin da ku ew yek mentiqî vegere.
Blokên hilberandina sînyala PLC-ê li rawestgeha Ewlekariya Kêm li cîhê pêşbaziyê bi heman rengî hatine rêz kirin, lê ji bo danîna nirxa guhêrbar #TEMP0, bes bû ku rêzika riya min a ninja di bloka DB1 de binivîsanda. Kontrolkirina nirxa di blokê de sade bû û ne hewceyî zanîna kûr a zimanê bernamesaziya blokê bû. Eşkere ye, di asta Ewlekariya Bilind de, bidestxistina kontrola destan dê pir dijwartir be û pêdivî ye ku meriv tevliheviyên zimanê STL (yek ji awayên bernamekirina S7 PLC) fam bike.
Reverse block FC3
Naveroka bloka FC3 di nûnertiya STL de:
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_VALKod pir dirêj e û dibe ku ji kesê ku bi STL re nenas tevlihev xuya bike. Di çarçoweya vê gotarê de analîzkirina her talîmatê tune ye û kapasîteyên zimanê STL di manuala têkildar de têne dîtin: . Li vir ez ê piştî pêvajoyê heman kodê pêşkêşî bikim - navên etîket û guherbaran biguherînim û şîroveyên ku algorîtmaya xebatê û hin avakirina zimanê STL vedibêjin zêde bikim. Bihêle ez tavilê zanibim ku bloka navborî makîneyek virtual heye ku hin bytekodên ku di bloka DB100 de cih digirin, naveroka ku em pê dizanin, pêk tîne. Talîmatên makîneya virtual ji 1 byte koda xebitandinê û bytes argumanan pêk tê, ji bo her argumanek yek byte. Hemî rêwerzên têne hesibandin du arguman hene ku min di şîroveyan de nirxên wan wekî X û Y destnîşan kirin.
Koda piştî pêvajoyê]
# Инициализация различных переменных
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_VALDema ku em ramanek ji rêwerzên makîneya virtual girt, ka em jihevdengek piçûk binivîsin da ku bitekodê di bloka DB100 de parsek bike:
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))
breakWekî encamek, em koda makîneya virtual ya jêrîn digirin:
Koda makîneya virtual
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)Wekî ku hûn dibînin, ev bername bi tenê her karakterek ji DB101 ji bo wekheviya nirxek diyarkirî kontrol dike. Rêza dawîn ji bo derbaskirina hemî kontrolan ev e: n0w u 4r3 7h3 m4573r. Ger ev xet di bloka DB101 de were danîn, wê hingê kontrola PLC-ya bi destan tê çalak kirin û dê gengaz be ku balonê biteqe an jî biteqe.
Navê pêger! Alexey zanînek bilind a ku hêjayî ninjayek pîşesaziyê ye nîşan da :) Me xelatên bîranîn ji serketî re şand. Gelek spas ji bo hemî beşdaran!
Source: www.habr.com
