Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

Á síðustu PHDays 9 héldum við keppni um að hakka inn gasdæluverksmiðju - keppni Iðnaðar Ninja. Það voru þrír standar á staðnum með mismunandi öryggisbreytur (No Security, Low Security, High Security), sem líkja eftir sama iðnaðarferli: lofti undir þrýstingi var dælt í blöðru (og síðan sleppt).

Þrátt fyrir mismunandi öryggisbreytur var vélbúnaðarsamsetning standanna sú sama: Siemens Simatic PLC S7-300 röð; neyðartæmingarhnappur og þrýstingsmælingarbúnaður (tengdur PLC stafrænum inntakum (DI)); lokar sem starfa fyrir uppblástur og tæmingu á lofti (tengdir stafrænum útgangum PLC (DO)) - sjá myndina hér að neðan.

Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

PLC, allt eftir þrýstingsmælingum og í samræmi við áætlun sína, tók ákvörðun um að tæma eða blása upp kúluna (opnaði og lokaði samsvarandi lokum). Hins vegar voru allir standar með handstýringu, sem gerði það mögulegt að stjórna stöðu ventla án nokkurra takmarkana.

Stöðurnar voru ólíkar að því hversu flókið það var að virkja þessa stillingu: á óvarða básnum var auðveldast að gera þetta og á High Security básnum var það að sama skapi erfiðara.

Fimm af sex vandamálum voru leyst á tveimur dögum; Þátttakandi í fyrsta sæti fékk 233 stig (hann var í viku í undirbúningi fyrir keppnina). Þrír sigurvegarar: I sæti - a1exdandy, II - Rubikoid, III - Ze.

Hins vegar, á PHDdays, tókst enginn þátttakenda að sigrast á öllum þremur básnum, svo við ákváðum að gera netkeppni og birtum erfiðasta verkefnið í byrjun júní. Þátttakendur þurftu að klára verkefnið innan mánaðar, finna fánann og lýsa lausninni ítarlega og á áhugaverðan hátt.

Fyrir neðan klippuna birtum við greiningu á bestu lausn verkefnisins frá þeim sem sendar voru yfir mánuðinn, það fannst Alexey Kovrizhnykh (a1exdandy) frá Digital Security fyrirtækinu, sem náði XNUMX. sæti í keppninni á PHDays. Hér að neðan kynnum við texta þess með athugasemdum okkar.

Frumgreining

Svo, verkefnið innihélt skjalasafn með eftirfarandi skrám:

  • block_upload_traffic.pcapng
  • DB100.bin
  • hints.txt

Hints.txt skráin inniheldur nauðsynlegar upplýsingar og vísbendingar til að leysa verkefnið. Hér er innihald þess:

  1. Petrovich sagði mér í gær að þú getur hlaðið kubba frá PlcSim inn í Step7.
  2. Siemens Simatic S7-300 röð PLC var notað á básnum.
  3. PlcSim er PLC keppinautur sem gerir þér kleift að keyra og kemba forrit fyrir Siemens S7 PLC.

DB100.bin skráin virðist innihalda DB100 PLC gagnablokkina: 00000000: 0100 0102 6e02 0401 0206 0100 0101 0102 ....n......... 00000010: 1002 0501 0202 2002 0501. ..... ......... 0206: 0100 0102 00000020 0102 7702 0401 0206 0100a0103 ..w............. 0102: 0 02 00000030 0501 0202 1602 0501 0206 ................ 0100: 0104 0102 00000040 7502 0401 0206 0100a0105 0102 u............... 0: 02 0501 00000050 0202 1602 0501 0206 0100............0106. 0102: 3402 4 00000060 0401 0206 0100 0107 0102 ......... & ..... 2602: 0501C0202 00000070 4 02 0501 0206 0100 0108 L ......... 0102. .. 3302 : 0401 3 00000080 0206 0100a0109 0102 0 02 ................ 0501: 0202 1602 00000090 0501a 0206 0100 010 0102 ........... 3702a0401: 0206 7b 000000 0 0100 010 0102 2202 ......".....F... 0501b0202: 4602 0501 000000c 0 0206 0100 ......... 010 0102 . .. 3302c0401: 0206d 0100 3a000000 0 010 0102 0 02 ................ 0501d0202: 1602 0501e 0206 000000d0 0100 010 0102 6 02 0401 0206 0100 . .... 010e000000: 0 0102 1102 0501 0202 2302 0501 0206 ........#...... 0100f000000: 0 0110 0102 3502 0401 0206 0100.....0111 0102 ..... ..... 5: 00000100 1202 0501 0202 2502 0501 0206 0100 ......%......... 0112: 00000110 0102 3302 0401 0206 0100 ....... .....&. 0113: 0102 2602 3c00000120 0501 0202 4 ....L......

Eins og nafnið gefur til kynna inniheldur block_upload_traffic.pcapng skráin dump af blokkupphleðsluumferð á PLC.

Þess má geta að örlítið erfiðara var að nálgast þessa umferðarþunga á keppnisstaðnum á ráðstefnunni. Til að gera þetta var nauðsynlegt að skilja handritið úr verkefnaskránni fyrir TeslaSCADA2. Út frá því var hægt að skilja hvar sorphaugurinn sem dulkóðaði með RC4 var staðsettur og hvaða lykil þurfti að nota til að afkóða hann. Hægt var að ná í gagnablokkir á staðnum með því að nota S7 samskiptareglur. Fyrir þetta notaði ég kynningarforritið úr Snap7 pakkanum.

Að draga merkjavinnslukubba úr umferðarhaug

Þegar þú skoðar innihald sorphaugsins geturðu skilið að það inniheldur merkjavinnslublokkir OB1, FC1, FC2 og FC3:

Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

Þessar blokkir verður að fjarlægja. Þetta er til dæmis hægt að gera með eftirfarandi skriftu, eftir að hafa áður breytt umferðinni úr pcapng sniðinu í 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 = ''

Eftir að hafa skoðað blokkirnar sem myndast muntu taka eftir því að þær byrja alltaf á bætum 70 70 (bls). Nú þarftu að læra hvernig á að greina þau. Verkefnavísbendingin gefur til kynna að þú þurfir að nota PlcSim fyrir þetta.

Að fá lesanlegar leiðbeiningar frá blokkum

Fyrst skulum við reyna að forrita S7-PlcSim með því að hlaða nokkrum kubbum með endurteknum leiðbeiningum (= Q 0.0) inn í það með því að nota Simatic Manager hugbúnaðinn og vista PLC sem fæst í keppinautnum í example.plc skrána. Með því að skoða innihald skrárinnar geturðu auðveldlega ákvarðað upphaf niðurhalaðra blokka með undirskriftinni 70 70, sem við uppgötvuðum áðan. Á undan blokkunum, greinilega, er blokkastærðin skrifuð sem 4-bæta lítið-endian gildi.

Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

Eftir að við fengum upplýsingar um uppbyggingu plc skráa birtist eftirfarandi aðgerðaáætlun til að lesa PLC S7 forrit:

  1. Með því að nota Simatic Manager búum við til blokkbyggingu í S7-PlcSim svipað þeirri sem við fengum frá sorphaugnum. Kubbastærðirnar verða að passa (þetta er náð með því að fylla kubbana með tilskildum fjölda leiðbeininga) og auðkenni þeirra (OB1, FC1, FC2, FC3).
  2. Vistaðu PLC í skrá.
  3. Við skiptum út innihaldi kubbanna í skránni sem myndast fyrir kubbana frá umferðarhaugnum. Upphaf kubbanna ræðst af undirskriftinni.
  4. Við hleðum skránni sem myndast í S7-PlcSim og skoðum innihald kubbanna í Simatic Manager.

Hægt er að skipta um blokkir, til dæmis, með eftirfarandi kóða:

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 fór kannski erfiðari, en samt rétta leið. Við gerðum ráð fyrir að þátttakendur myndu nota NetToPlcSim forritið þannig að PlcSim gæti haft samskipti yfir netið, hlaðið upp kubbum á PlcSim í gegnum Snap7 og síðan hlaðið niður þessum kubbum sem verkefni frá PlcSim með því að nota þróunarumhverfið.

Með því að opna skrána sem myndast í S7-PlcSim geturðu lesið yfirskrifuðu blokkina með því að nota Simatic Manager. Helstu tækjastýringaraðgerðir eru skráðar í blokk FC1. Sérstaklega athyglisvert er #TEMP0 breytan, sem þegar kveikt er á henni virðist stilla PLC-stýringuna á handvirka stillingu byggt á M2.2 og M2.3 bita minnisgildum. #TEMP0 gildið er stillt af aðgerð FC3.

Í fótspor Industrial Ninja: hvernig var brotist inn á PLC á Positive Hack Days 9

Til að leysa vandamálið þarftu að greina FC3 aðgerðina og skilja hvað þarf að gera svo hún skili rökréttu.

PLC merkjavinnslukubbunum á Low Security básnum á keppnisstað var raðað á svipaðan hátt, en til að stilla gildi #TEMP0 breytunnar var nóg að skrifa línuna mína ninja inn í DB1 blokkina. Að athuga gildið í blokk var einfalt og krafðist ekki djúprar þekkingar á forritunarmáli blokkarinnar. Augljóslega, á háu öryggisstigi, verður mun erfiðara að ná handvirkri stjórn og það er nauðsynlegt að skilja ranghala STL tungumálsins (ein af leiðunum til að forrita S7 PLC).

Reverse blokk FC3

Innihald FC3 blokkarinnar í STL framsetningu:

      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

Kóðinn er nokkuð langur og kann að virðast flókinn fyrir einhvern sem ekki kannast við STL. Það þýðir ekkert að greina hverja kennslu innan ramma þessarar greinar; nákvæmar leiðbeiningar og getu STL tungumálsins er að finna í samsvarandi handbók: Yfirlýsingalisti (STL) fyrir S7-300 og S7-400 forritun. Hér mun ég kynna sama kóða eftir vinnslu - endurnefna merkin og breyturnar og bæta við athugasemdum sem lýsa aðgerðalgríminu og sumum STL tungumálabyggingum. Leyfðu mér strax að hafa í huga að viðkomandi blokk inniheldur sýndarvél sem keyrir einhvern bætikóða sem staðsettur er í DB100 blokkinni, innihaldið sem við þekkjum. Sýndarvélaleiðbeiningar samanstanda af 1 bæti af rekstrarkóða og bæti af breytum, einu bæti fyrir hverja breytu. Allar álitnar leiðbeiningar hafa tvö rök; ég tilgreindi gildi þeirra í athugasemdunum sem X og Y.

Kóði eftir vinnslu]

# Инициализация различных переменных
      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

Eftir að hafa fengið hugmynd um sýndarvélaleiðbeiningarnar, skulum við skrifa lítinn sundur til að flokka bætikóðann í DB100 blokkinni:

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

Fyrir vikið fáum við eftirfarandi sýndarvélarkóða:

Kóði sýndarvélar

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)

Eins og þú sérð, athugar þetta forrit einfaldlega hvern staf úr DB101 fyrir jafnrétti að ákveðnu gildi. Lokalínan til að standast allar athuganir er: n0w u 4r3 7h3 m4573r. Ef þessi lína er sett í blokk DB101, þá er handvirk PLC-stýring virkjuð og hægt verður að sprengja eða tæma blöðruna.


Það er allt og sumt! Alexey sýndi mikla þekkingu sem er verðug iðnaðarninja :) Við sendum eftirminnileg verðlaun til sigurvegarans. Kærar þakkir til allra þátttakenda!

Heimild: www.habr.com

Bæta við athugasemd