صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

آخري پي ايڇ ڊي 9 تي اسان گيس پمپنگ پلانٽ کي هيڪ ڪرڻ لاءِ هڪ مقابلو منعقد ڪيو - مقابلو صنعتي ننجا. سائيٽ تي ٽي اسٽينڊ هئا مختلف حفاظتي پيٽرولن سان (نه سيڪيورٽي، گهٽ سيڪيورٽي، هاء سيڪيورٽي)، ساڳئي صنعتي عمل کي نقل ڪندي: دٻاء هيٺ هوا کي هڪ بالون ۾ پمپ ڪيو ويو (۽ پوء آزاد ڪيو ويو).

مختلف حفاظتي معيارن جي باوجود، اسٽينڊن جي هارڊويئر جو ٺهيل ساڳيو هو: Siemens Simmatic PLC S7-300 سيريز؛ ايمرجنسي ڊيفليشن بٽڻ ۽ پريشر ماپڻ وارو ڊيوائس (پي ايل سي ڊجيٽل انپٽس سان ڳنڍيل (DI))؛ والوز جيڪي ڪم ڪن ٿا انفليشن ۽ هوا جي گھٽتائي لاءِ (پي ايل سي (DO) جي ڊجيٽل آئوٽ سان ڳنڍيل) - هيٺ ڏنل شڪل ڏسو.

صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

پي ايل سي، پريشر ريڊنگز جي بنياد تي ۽ ان جي پروگرام جي مطابق، بال کي ڊفالٽ يا فليٽ ڪرڻ جو فيصلو ڪيو (ساڳئي والوز کوليو ۽ بند ڪيو). بهرحال، سڀني اسٽينڊن کي دستياب ڪنٽرول موڊ هو، جنهن کي ڪنهن به پابنديون بغير والوز جي رياستن کي ڪنٽرول ڪرڻ ممڪن بڻائي.

ھن موڊ کي چالو ڪرڻ جي پيچيدگي ۾ موقف مختلف آھن: غير محفوظ ٿيل اسٽينڊ تي اھو ڪرڻ آسان ھو، ۽ ھاء سيڪيورٽي اسٽينڊ تي اھو وڌيڪ ڏکيو ھو.

ڇهن مان پنج مسئلا ٻن ڏينهن ۾ حل ٿي ويا. پهرين جڳهه جي شرڪت ڪندڙ 233 پوائنٽس حاصل ڪيا (هن مقابلي جي تياري ۾ هڪ هفتي گذاريو). ٽي فاتح: آئون جڳهه - a1exdandy، II - Rubikoid، III - Ze.

بهرحال، PHDays دوران، شرڪت ڪندڙن مان ڪو به ٽنھي اسٽينڊن تي غالب نه آيو، تنھنڪري اسان ھڪ آن لائن مقابلو ڪرڻ جو فيصلو ڪيو ۽ سڀ کان ڏکيو ڪم جون جي شروعات ۾ شايع ڪيو. شرڪت ڪندڙن کي ھڪڙي مھيني اندر ڪم مڪمل ڪرڻو ھو، جھنڊو ڳوليو، ۽ حل کي تفصيل سان ۽ دلچسپ انداز ۾ بيان ڪيو.

هيٺ ڏنل ڪٽ جي هيٺان اسان هڪ تجزيو شايع ڪريون ٿا بهترين حل جو تجزيو جيڪو هن مهيني ۾ موڪليو ويو آهي، اهو ڊجيٽل سيڪيورٽي ڪمپني جي Alexey Kovrizhnykh (a1exdandy) پاران مليو، جنهن پي ايڇ ڊيز دوران مقابلي ۾ پهرين جڳهه ورتي. هيٺ اسان ان جو متن پنهنجي راين سان پيش ڪريون ٿا.

شروعاتي تجزيو

تنهن ڪري، ڪم هيٺ ڏنل فائلن سان گڏ هڪ آرڪائيو تي مشتمل آهي:

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

hints.txt فائل ۾ ڪم کي حل ڪرڻ لاءِ ضروري معلومات ۽ اشارا شامل آھن. هتي ان جا مواد آهن:

  1. پيٽرووچ مون کي ڪالهه ٻڌايو ته توهان PlcSim کان اسٽيپ 7 ۾ بلاڪ لوڊ ڪري سگهو ٿا.
  2. Siemens Simmatic S7-300 سيريز PLC اسٽينڊ تي استعمال ڪيو ويو.
  3. PlcSim هڪ PLC ايموليٽر آهي جيڪو توهان کي سيمينس S7 PLCs لاءِ پروگرام هلائڻ ۽ ڊيبگ ڪرڻ جي اجازت ڏئي ٿو.

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 00000040a7502 0401 u............... 0206: 0100 0105 0102 0 02 0501 00000050 0202............ 1602. 0501: 0206 0100 0106 0102 3402 4 ......... 00000060 0401 0206 0100 0107 : 0102 2602 0501 0202 00000070a4 02 0501 0206 ................ 0100: 0108 0102 3302 0401a 3 00000080 0206 0100 ......... . .. 0109c0102: 0d 02 0501a0202 1602 00000090 0501 0206 0100 ................ 010d0102: 3702 0401e 0206 7d000000 0 0100 010 0102 2202 0501 0202 4602 0501 .... 000000e0: 0206 0100 010 0102 3302 0401 0206 0100 ........#...... 3f000000: 0 010 0102 0 02 0501..... ..... 0202: 1602 0501 0206 000000 0 0100 010 0102 ......٪......... 6: 02 0401 0206 0100 010 000000..... .....& 0: 0102 1102 0501c0202 2302 0501 0206 .... ايل ......

جيئن ته نالو مشورو ڏئي ٿو، block_upload_traffic.pcapng فائل PLC ڏانهن بلاڪ اپ لوڊ ٽرئفڪ جو هڪ ڊمپ تي مشتمل آهي.

اهو قابل ذڪر آهي ته ڪانفرنس دوران مقابلي واري سائيٽ تي هي ٽرئفڪ ڊمپ حاصل ڪرڻ ۾ ٿورو وڌيڪ ڏکيو هو. هن کي ڪرڻ لاء، اهو ضروري هو ته اسڪرپٽ سمجھڻ لاء پروجيڪٽ فائل مان TeslaSCADA2. ان مان اهو سمجهڻ ممڪن هو ته RC4 استعمال ڪندي انڪرپٽ ٿيل ڊمپ ڪٿي واقع هو ۽ ان کي ختم ڪرڻ لاءِ ڪهڙي ڪنجي کي استعمال ڪرڻ جي ضرورت آهي. سائيٽ تي ڊيٽا بلاڪ جا ڊمپ حاصل ڪري سگھجن ٿا S7 پروٽوڪول ڪلائنٽ استعمال ڪندي. ان لاءِ مون Snap7 پيڪيج مان ڊيمو ڪلائنٽ استعمال ڪيو.

ٽرئفڪ ڊمپ مان سگنل پروسيسنگ بلاڪ ڪڍڻ

ڊمپ جي مواد کي ڏسي، توهان سمجهي سگهو ٿا ته ان ۾ سگنل پروسيسنگ بلاڪ OB1، FC1، FC2 ۽ FC3 شامل آهن:

صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

اهي بلاڪ ختم ٿيڻ گهرجن. اهو ٿي سگهي ٿو، مثال طور، هيٺ ڏنل اسڪرپٽ سان، اڳ ۾ ٽرئفڪ کي 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 (pp) سان شروع ٿين ٿا. هاڻي توهان کي سکڻ جي ضرورت آهي ته انهن جو تجزيو ڪيئن ڪجي. تفويض جو اشارو مشورو ڏئي ٿو ته توهان کي هن لاءِ PlcSim استعمال ڪرڻ جي ضرورت آهي.

بلاڪ مان انساني پڙهڻ جي قابل هدايتون حاصل ڪرڻ

پهرين، اچو ته پروگرام ڪرڻ جي ڪوشش ڪريون S7-PlcSim ڪيترن ئي بلاڪن کي لوڊ ڪندي ان ۾ ورجائيندڙ هدايتون (= Q 0.0) سان ان ۾ Simmatic Manager سافٽ ويئر استعمال ڪندي، ۽ ايموليٽر ۾ حاصل ڪيل PLC کي example.plc فائل ۾ محفوظ ڪريون. فائل جي مواد کي ڏسڻ سان، توهان آساني سان ڊائون لوڊ ٿيل بلاڪ جي شروعات کي طئي ڪري سگھو ٿا دستخط 70 70، جيڪو اسان اڳ ۾ دريافت ڪيو. بلاڪ کان اڳ، ظاهري طور تي، بلاڪ سائيز 4-byte ننڍي-انڊين قدر جي طور تي لکيو ويو آهي.

صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

plc فائلن جي ڍانچي جي باري ۾ معلومات حاصل ڪرڻ کان پوءِ، PLC S7 پروگرامن کي پڙهڻ لاءِ هيٺيون ايڪشن پلان ظاهر ٿيو:

  1. سميٽيڪل مئنيجر کي استعمال ڪندي، اسان S7-PlcSim ۾ هڪ بلاڪ ڍانچي ٺاهيندا آهيون جيئن اسان ڊمپ مان حاصل ڪيو. بلاڪ جي سائزن کي ملائڻ گھرجي (اھو ھدايتن جي گھربل تعداد سان بلاڪن کي ڀرڻ سان حاصل ڪيو ويندو آھي) ۽ انھن جي سڃاڻپ ڪندڙ (OB1, FC1, FC2, FC3).
  2. PLC کي فائل ۾ محفوظ ڪريو.
  3. اسان نتيجن واري فائل ۾ بلاڪ جي مواد کي ٽرئفڪ ڊمپ مان بلاڪ سان تبديل ڪريون ٿا. بلاڪ جي شروعات دستخط جي ذريعي مقرر ڪئي وئي آهي.
  4. اسان نتيجن واري فائل کي S7-PlcSim ۾ لوڊ ڪريون ٿا ۽ سماٽ مئنيجر ۾ بلاڪ جي مواد کي ڏسو.

بلاڪ کي تبديل ڪري سگھجي ٿو، مثال طور، ھيٺ ڏنل ڪوڊ سان:

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 هڪ وڌيڪ ڏکيو، پر اڃا به صحيح رستو ورتو. اسان فرض ڪيو ته شرڪت ڪندڙ NetToPlcSim پروگرام استعمال ڪندا ته جيئن PlcSim نيٽ ورڪ تي ڳالھ ٻولھ ڪري سگھي، Snap7 ذريعي PlcSim تي بلاڪ اپلوڊ ڪري، ۽ پوءِ ڊولپمينٽ ماحول استعمال ڪندي PlcSim کان پروجيڪٽ جي طور تي انھن بلاڪن کي ڊائون لوڊ ڪري سگھن.

S7-PlcSim ۾ نتيجي واري فائل کي کولڻ سان، توھان پڙھي سگھوٿا اوور رائٽ ٿيل بلاڪس کي استعمال ڪندي Simmatic Manager. مکيه ڊوائيس ڪنٽرول افعال بلاڪ FC1 ۾ رڪارڊ ٿيل آهن. خاص طور تي نوٽ #TEMP0 متغير آهي، جيڪو جڏهن آن ڪيو وڃي ٿو PLC ڪنٽرول کي مينوئل موڊ تي M2.2 ۽ M2.3 بٽ ميموري ويلز جي بنياد تي سيٽ ڪرڻ لاءِ. #TEMP0 قدر مقرر ٿيل آھي فنڪشن FC3 ذريعي.

صنعتي ننجا جي قدمن ۾: ڪيئن پي ايل سي کي هيڪ ڪيو ويو مثبت هيڪ ڏينهن 9

مسئلو حل ڪرڻ لاء، توهان کي FC3 فنڪشن جو تجزيو ڪرڻ جي ضرورت آهي ۽ سمجھڻ جي ضرورت آهي ته ڇا ڪيو وڃي ته اهو هڪ منطقي هڪ واپسي.

مقابلي واري سائيٽ تي گھٽ سيڪيورٽي اسٽينڊ تي پي ايل سي سگنل پروسيسنگ بلاڪ ساڳئي طرح ترتيب ڏنل هئا، پر #TEMP0 متغير جي قيمت مقرر ڪرڻ لاء، اهو ڪافي هو ته منهنجي ننجا طريقي سان ڊي بي 1 بلاڪ ۾ لکت. ھڪڙي بلاڪ ۾ قيمت جي جانچ ڪرڻ بلڪل سادو ھو ۽ بلاڪ پروگرامنگ ٻولي جي گھڻي ڄاڻ جي ضرورت نه ھئي. ظاهر آهي، هاء سيڪيورٽي سطح تي، دستياب ڪنٽرول حاصل ڪرڻ تمام گهڻو ڏکيو هوندو ۽ اهو ضروري آهي ته 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 ٻولي جون صلاحيتون لاڳاپيل دستياب ۾ ملي سگهن ٿيون: بيان جي فهرست (STL) S7-300 ۽ S7-400 پروگرامنگ لاءِ. هتي مان پروسيسنگ کان پوءِ ساڳيو ڪوڊ پيش ڪندس - ليبلز ۽ متغيرن جو نالو مٽائڻ ۽ آپريشن الگورٿم ۽ ڪجهه 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

ورچوئل مشين جي هدايتن جو هڪ خيال حاصل ڪرڻ بعد، اچو ته هڪ ننڍڙو disassembler لکون بائيٽ ڪوڊ کي ڊي بي 100 بلاڪ ۾ پارس ڪرڻ لاءِ:

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 ڪنٽرول چالو ٿي ويندو ۽ اهو ڦاٽڻ يا ڦاٽڻ ممڪن ٿيندو.


اهو ئي سڀ ڪجهه آهي! Alexey هڪ صنعتي ننجا جي لائق علم جي اعلي سطح جو مظاهرو ڪيو :) اسان فاتح کي يادگار انعام موڪليا. سڀني شرڪت ڪندڙن جي وڏي مهرباني!

جو ذريعو: www.habr.com

تبصرو شامل ڪريو