Op 'e lêste PHDays 9 hawwe wy in kompetysje hâlden om in gaspompynstallaasje te hacken - kompetysje
Nettsjinsteande de ferskillende feiligens parameters wie de hardware gearstalling fan de tribunes itselde: Siemens Simatic PLC S7-300 rige; emergency deflation knop en druk mjitapparaat (ferbûn mei PLC digitale yngongen (DI)); kleppen wurkje foar ynflaasje en deflation fan lucht (ferbûn mei de digitale útgongen fan de PLC (DO)) - sjoch de figuer hjirûnder.
De PLC hat, ôfhinklik fan 'e druklêzingen en yn oerienstimming mei har programma, in beslút makke om de bal te leegjen of op te blazen (iepene en slute de oerienkommende kleppen). Lykwols, alle tribunes hiene in hânmjittich kontrôle modus, dat makke it mooglik om te kontrolearjen de steat fan de kleppen sûnder beheinings.
De tribunes ferskille yn 'e kompleksiteit fan it ynskeakeljen fan dizze modus: op 'e ûnbeskerme stand wie it it maklikst om dit te dwaan, en op 'e High Security-stand wie it navenant dreger.
Fiif fan de seis problemen binne yn twa dagen oplost; De dielnimmer op it earste plak fertsjinne 233 punten (hy brocht in wike tariede op de kompetysje). Trije winners: I plak - a1exdandy, II - Rubikoid, III - Ze.
Lykwols, tidens PHDays koe gjinien fan 'e dielnimmers alle trije tribunes oerwinne, dus besleaten wy in online kompetysje te meitsjen en begjin juny de dreechste taak publisearre. Dielnimmers moasten de taak binnen in moanne ôfmeitsje, de flagge fine en de oplossing yn detail en op in nijsgjirrige wize beskriuwe.
Under de besuniging publisearje wy in analyze fan 'e bêste oplossing foar de taak fan dyjingen dy't oer de moanne ferstjoerd binne, it waard fûn troch Alexey Kovrizhnykh (a1exdandy) fan it bedriuw Digital Security, dy't it XNUMXe plak yn 'e konkurrinsje naam tidens PHDays. Hjirûnder presintearje wy syn tekst mei ús opmerkingen.
Inisjele analyze
Dat, de taak befette in argyf mei de folgjende bestannen:
- block_upload_traffic.pcapng
- DB100.bin
- hints.txt
It hints.txt-bestân befettet de nedige ynformaasje en hints om de taak op te lossen. Hjir binne de ynhâld:
- Petrovich fertelde my juster dat jo blokken fan PlcSim kinne laden yn Step7.
- De Siemens Simatic S7-300 rige PLC waard brûkt by de stand.
- PlcSim is in PLC-emulator wêrmei jo programma's kinne útfiere en debuggen foar Siemens S7 PLC's.
It DB100.bin-bestân liket it DB100 PLC-gegevensblok te befetsjen: 00000000: 0100 0102 6e02 0401 0206 0100 0101 0102 ....n......... 00000010: 1002 0501 0202 2002 0501 0206 . ..... ......... 0100: 0102 00000020 0102 7702 0401 0206 0100 0103a0102 ..w............. ................ 0: 02 00000030 0501 0202 1602 0501 0206a0100 0104 u............ 0102 00000040............7502. 0401: 0206 0100 0105 0102 0 02 0501 00000050 0202 ...............1602 0501 0206 0100 0106 0102 3402 4 00000060 L ......... 0401. .. 0206 : 0100 0107 0102 2602 0501a0202 00000070 4 02 ................ 0501: 0206 0100 0108 0102a 3302 0401 3 00000080 .......... 0206a0100: 0109 0102b 0 02 0501 0202 1602 00000090 ......".....F... 0501b0206: 0100 010 0102c 3702 0401 0206 7 ... … .... 000000e0: 0100 010 0102 2202 0501 0202 4602 0501 ........#...... 000000f0: 0206 0100 010 0102 3302 0401 0206.....0100 3 000000 0..... ..... 010: 0102 0 02 0501 0202 1602 0501 0206 ......%......... 000000: 0 0100 010 0102 6 02 0401 ..... .....&. 0206: 0100 010 000000c0 0102 1102 0501 ....L......
Lykas de namme al fermoeden docht, befettet de block_upload_traffic.pcapng-bestân in dump fan blok-uploadferkear nei de PLC.
It is de muoite wurdich op te merken dat dizze ferkearsdump op 'e konkurrinsjeside tidens de konferinsje wat dreger wie te krijen. Om dit te dwaan, wie it nedich om it skript te begripen fan it projektbestân foar TeslaSCADA2. Dêrút wie it mooglik om te begripen wêr't de dump fersifere mei RC4 siet en hokker kaai moast wurde brûkt om it te ûntsiferjen. Dumps fan gegevensblokken op side koenen wurde krigen mei de S7-protokolclient. Hjirfoar brûkte ik de demo-kliïnt fan it Snap7-pakket.
It útheljen fan sinjaalferwurkingsblokken fan in ferkearsdump
Sjoch nei de ynhâld fan 'e dump, kinne jo begripe dat it sinjaalferwurkingsblokken OB1, FC1, FC2 en FC3 befettet:
Dizze blokken moatte fuortsmiten wurde. Dit kin bygelyks dien wurde mei it folgjende skript, nei't it ferkear earder konvertearre is fan it pcapng-formaat nei 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 = ''
Nei't jo de resultearjende blokken hawwe ûndersocht, sille jo merke dat se altyd begjinne mei bytes 70 70 (pp). No moatte jo leare hoe't jo se analysearje. De opdracht hint suggerearret dat jo hjirfoar PlcSim moatte brûke.
It krijen fan minsklik lêsbere ynstruksjes út blokken
Litte wy earst besykje S7-PlcSim te programmearjen troch ferskate blokken te laden mei werheljende ynstruksjes (= Q 0.0) yn it mei Simatic Manager-software, en bewarje de PLC dy't yn 'e emulator krigen is yn' e example.plc-bestân. Troch nei de ynhâld fan it bestân te sjen, kinne jo it begjin fan 'e downloade blokken maklik bepale troch de hantekening 70 70, dy't wy earder ûntdutsen. Foardat de blokken, blykber, de blokgrutte wurdt skreaun as in 4-byte little-endian wearde.
Nei't wy ynformaasje krigen hawwe oer de struktuer fan plc-bestannen, ferskynde it folgjende aksjeplan foar it lêzen fan PLC S7-programma's:
- Mei help fan Simatic Manager meitsje wy in blokstruktuer yn S7-PlcSim fergelykber mei dejinge dy't wy krigen fan 'e dump. De blokgrutte moat oerienkomme (dit wurdt berikt troch it foljen fan de blokken mei it fereaske oantal ynstruksjes) en har identifiers (OB1, FC1, FC2, FC3).
- Bewarje de PLC nei in bestân.
- Wy ferfange de ynhâld fan 'e blokken yn' e resultearjende triem mei de blokken fan 'e ferkearsdump. It begjin fan 'e blokken wurdt bepaald troch de hantekening.
- Wy lade de resultearjende triem yn S7-PlcSim en besjoch de ynhâld fan 'e blokken yn Simatic Manager.
Blokken kinne wurde ferfongen, bygelyks, mei de folgjende koade:
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 naam in miskien dreger, mar dochs korrekt paad. Wy geane derfan út dat dielnimmers it programma NetToPlcSim soene brûke, sadat PlcSim koe kommunisearje oer it netwurk, blokken uploade nei PlcSim fia Snap7, en dan dizze blokken downloade as in projekt fan PlcSim mei de ûntwikkelingsomjouwing.
Troch it resultearjende bestân yn S7-PlcSim te iepenjen, kinne jo de oerskreaune blokken lêze mei de Simatic Manager. De haadfunksjes foar apparaatkontrôle wurde opnommen yn blok FC1. Fan bysûndere notysje is de fariabele #TEMP0, dy't as ynskeakele liket de PLC-kontrôle yn te stellen yn 'e manuele modus basearre op de M2.2- en M2.3-bit-ûnthâldwearden. De wearde #TEMP0 wurdt ynsteld troch funksje FC3.
Om it probleem op te lossen, moatte jo de FC3-funksje analysearje en begripe wat der dien wurde moat, sadat it in logyske werombringt.
De PLC-sinjaalferwurkingsblokken op 'e Low Security-stand op' e konkurrinsjeside waarden op in fergelykbere manier regele, mar om de wearde fan 'e #TEMP0-fariabele yn te stellen, wie it genôch om de line myn ninja-wei yn it DB1-blok te skriuwen. It kontrolearjen fan de wearde yn in blok wie ienfâldich en frege gjin djippe kennis fan 'e blokprogrammearringstaal. Fansels sil op it nivo fan hege feiligens it realisearjen fan manuele kontrôle folle dreger wêze en it is nedich om de yngewikkeldheden fan 'e STL-taal te begripen (ien fan 'e manieren om de S7 PLC te programmearjen).
Omkearblok FC3
Ynhâld fan it FC3-blok yn STL-fertsjintwurdiging:
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
De koade is frij lang en kin lykje yngewikkeld foar immen net bekend mei STL. It hat gjin punt om elke ynstruksje te analysearjen yn it ramt fan dit artikel; detaillearre ynstruksjes en mooglikheden fan 'e STL-taal kinne fûn wurde yn' e oerienkommende hantlieding:
Koade nei ferwurking]
# Инициализация различных переменных
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
Nei't wy in idee hawwe fan 'e ynstruksjes foar firtuele masines, litte wy in lytse disassembler skriuwe om de bytekoade yn it DB100-blok te parsearjen:
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
As gefolch krije wy de folgjende firtuele masinekoade:
Firtuele masine koade
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)
Sa't jo sjen kinne, kontrolearret dit programma gewoan elk karakter fan DB101 foar gelikensens oan in bepaalde wearde. De lêste rigel foar it trochjaan fan alle kontrôles is: n0w u 4r3 7h3 m4573r. As dizze line wurdt pleatst yn blok DB101, dan wurdt hânmjittich PLC kontrôle aktivearre en it sil mooglik te eksplodearjen of deflate de ballon.
Da's alles! Alexey demonstrearre in heech nivo fan kennis weardich fan in yndustriële ninja :) Wy stjoerde memorabele prizen nei de winner. Tige tank oan alle dielnimmers!
Boarne: www.habr.com