Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

Акыркы PHDays 9да биз газ соргуч заводду бузуп алуу боюнча сынак өткөрдүк Industrial Ninja. Сайтта бир эле өнөр жай процессин туураган ар кандай коопсуздук параметрлери (Коопсуздук жок, Төмөн коопсуздук, Жогорку коопсуздук) болгон үч стенд бар болчу: басым астында аба шарга айдалып (андан кийин бошотулган).

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

Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

PLC басымдын көрсөткүчтөрүнө жараша жана анын программасына ылайык, шарды өчүрүү же толтуруу чечимин кабыл алды (тиешелүү клапандарды ачып, жапты). Бирок бардык стенддерде кол менен башкаруу режими болгон, бул клапандардын абалын эч кандай чектөөсүз башкарууга мүмкүндүк берген.

Стенддер бул режимди иштетүүнүн татаалдыгы менен айырмаланган: корголбогон стендде муну жасоо эң оңой, ал эми Жогорку коопсуздук стендинде тиешелүүлүгүнө жараша кыйыныраак болгон.

Алты маселенин бешөө эки күндө чечилди; Биринчи орунду ээлеген катышуучу 233 упайга ээ болду (ал сынакка бир жума даярданган). Үч жеңүүчү: I орун – а1ексданды, II – Рубикоид, III – Зе.

Бирок, PHDays учурунда катышуучулардын бири дагы үч стендди жеңе алган жок, ошондуктан биз онлайн сынак өткөрүүнү чечтик жана июнь айынын башында эң татаал тапшырманы жарыяладык. Катышуучулар тапшырманы бир айдын ичинде бүтүрүп, туу таап, чечүү жолун кеңири жана кызыктуу баяндап бериши керек болчу.

Кесиптин ылдый жагында биз бир айдын ичинде жөнөтүлгөн тапшырманын эң жакшы чечиминин анализин жарыялайбыз, аны PHDays учурунда сынакта 1-орунду алган Digital Security компаниясынан Алексей Коврижных (aXNUMXexdandy) тапты. Төмөндө анын текстин комментарийлерибиз менен сунуштайбыз.

Баштапкы анализ

Ошентип, тапшырма төмөнкү файлдар менен архивди камтыйт:

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

hints.txt файлы тапшырманы чечүү үчүн керектүү маалыматты жана кеңештерди камтыйт. Бул жерде анын мазмуну:

  1. Петрович кечээ мага блокторду PlcSimден Step7ге жүктөй аласың деп айтты.
  2. Стендде Siemens Simatic S7-300 series PLC колдонулган.
  3. 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 сигналдарды иштетүү блоктору бар экенин түшүнүүгө болот:

Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

Бул блокторду алып салуу керек. Муну, мисалы, трафикти 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-байт аз-эндиан мааниси катары жазылган.

Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

PLC файлдарынын түзүмү жөнүндө маалымат алгандан кийин, PLC S7 программаларын окуу үчүн төмөнкү иш-аракеттер планы пайда болду:

  1. Simatic Менеджерди колдонуп, биз S7-PlcSimде таштандыдан алганга окшош блок структурасын түзөбүз. Блоктун өлчөмдөрү дал келиши керек (бул блокторду керектүү сандагы нускамалар менен толтуруу менен жетишилет) жана алардын идентификаторлору (OB1, FC1, FC2, FC3).
  2. PLCти файлга сактаңыз.
  3. Биз пайда болгон файлдагы блоктордун мазмунун трафик таштандысынан алынган блокторго алмаштырабыз. Блоктордун башталышы кол менен аныкталат.
  4. Алынган файлды 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 функциясы тарабынан коюлган.

Industrial Ninjaнын изи менен: Positive Hack Days 9-да PLC кантип бузулган

Маселени чечүү үчүн, сиз 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 менен тааныш эмес бирөө үчүн татаал сезилиши мүмкүн. Бул макаланын алкагында ар бир нускаманы талдап чыгуунун эч кандай мааниси жок. S7-300 жана S7-400 программалоо үчүн билдирүүлөр тизмеси (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

DDoS коргоосу, VPS VDS серверлери бар сайттар үчүн ишенимдүү хостинг сатып алыңыз 🔥 DDoS коргоосу, VPS VDS серверлери бар ишенимдүү веб-сайт хостингин сатып алыңыз | ProHoster