انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 9 میں PLC کو کیسے ہیک کیا گیا

انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 9 میں PLC کو کیسے ہیک کیا گیا

آخری PHDays 9 میں ہم نے گیس پمپنگ پلانٹ کو ہیک کرنے کے لیے ایک مقابلہ منعقد کیا۔ صنعتی ننجا. سائٹ پر تین اسٹینڈز تھے جن میں مختلف سیکیورٹی پیرامیٹرز تھے (کوئی سیکیورٹی نہیں، کم سیکیورٹی، ہائی سیکیورٹی)، اسی صنعتی عمل کی تقلید کرتے ہوئے: دباؤ کے تحت ہوا کو غبارے میں ڈالا گیا (اور پھر چھوڑ دیا گیا)۔

مختلف حفاظتی پیرامیٹرز کے باوجود، اسٹینڈز کی ہارڈ ویئر کی ترکیب ایک جیسی تھی: سیمنز سیمیٹک PLC S7-300 سیریز؛ ایمرجنسی ڈیفلیشن بٹن اور پریشر ماپنے والا آلہ (PLC ڈیجیٹل ان پٹ (DI) سے منسلک)؛ مہنگائی اور ہوا کی تنزلی کے لیے کام کرنے والے والوز (PLC (DO) کے ڈیجیٹل آؤٹ پٹس سے منسلک) - نیچے دی گئی تصویر دیکھیں۔

انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 9 میں PLC کو کیسے ہیک کیا گیا

PLC نے، پریشر ریڈنگ پر منحصر ہے اور اپنے پروگرام کے مطابق، گیند کو ڈیفلیٹ کرنے یا فلانے کا فیصلہ کیا (متعلقہ والوز کو کھولا اور بند کیا)۔ تاہم، تمام اسٹینڈز میں دستی کنٹرول موڈ تھا، جس نے بغیر کسی پابندی کے والوز کی حالتوں کو کنٹرول کرنا ممکن بنایا۔

اس موڈ کو فعال کرنے کی پیچیدگی میں اسٹینڈز مختلف تھے: غیر محفوظ اسٹینڈ پر یہ کرنا سب سے آسان تھا، اور ہائی سیکیورٹی اسٹینڈ پر یہ اسی مناسبت سے زیادہ مشکل تھا۔

چھ میں سے پانچ مسائل دو دن میں حل ہو گئے۔ پہلی پوزیشن حاصل کرنے والے نے 233 پوائنٹس حاصل کیے (اس نے مقابلے کی تیاری میں ایک ہفتہ گزارا)۔ تین فاتح: میں جگہ دیتا ہوں - a1exdandy، II - Rubikoid، III - Ze۔

تاہم، PHDays کے دوران، شرکاء میں سے کوئی بھی تینوں اسٹینڈز پر قابو نہیں پا سکا، اس لیے ہم نے ایک آن لائن مقابلہ کرنے کا فیصلہ کیا اور جون کے اوائل میں سب سے مشکل کام شائع کیا۔ شرکاء کو ایک ماہ کے اندر ٹاسک مکمل کرنا تھا، جھنڈا ڈھونڈنا تھا، اور تفصیل سے اور دلچسپ انداز میں حل بیان کرنا تھا۔

کٹ کے نیچے ہم مہینے بھر بھیجے گئے کام کے بہترین حل کا تجزیہ شائع کرتے ہیں، یہ ڈیجیٹل سیکیورٹی کمپنی کے Alexey Kovrizhnykh (a1exdandy) نے پایا، جس نے PHDays کے دوران مقابلے میں پہلی پوزیشن حاصل کی۔ ذیل میں ہم اس کا متن اپنے تبصروں کے ساتھ پیش کرتے ہیں۔

ابتدائی تجزیہ

لہذا، کام میں مندرجہ ذیل فائلوں کے ساتھ ایک محفوظ شدہ دستاویزات شامل ہیں:

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

hints.txt فائل میں کام کو حل کرنے کے لیے ضروری معلومات اور اشارے شامل ہیں۔ اس کے مندرجات یہ ہیں:

  1. پیٹرووچ نے کل مجھے بتایا کہ آپ PlcSim سے Step7 میں بلاکس لوڈ کر سکتے ہیں۔
  2. سیمنز سیمیٹک S7-300 سیریز PLC اسٹینڈ پر استعمال کی گئی تھی۔
  3. PlcSim ایک PLC ایمولیٹر ہے جو آپ کو Siemens 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 0102a7702 ..w............. ................0401:0206 0100 0103 0102 0 02 00000030a0501 0202 u............... 1602: 0501 0206 0100 0104 0102 00000040 7502............ 0401۔ 0206: 0100 0105 0102 0 02 0501 00000050 0202 ......... & ..... 1602: 0501C0206 0100 0106 0102 3402 4 00000060 0401 L ......... 0206. .. 0100 : 0107 0102 2602 0501 0202a00000070 4 02 0501 ................ 0206: 0100 0108 0102 3302a 0401 3 00000080 0206 .......... 0100a0109: 0102 0b 02 0501 0202 1602 00000090 0501 ......".....F... 0206b0100: 010 0102 3702c 0401 0206 7 .... … .... 000000e0: 0100 010 0102 2202 0501 0202 4602 0501 ........#...... 000000f0: 0206 0100 010 0102 3302 0401..... ... .....&. 0206: 0100 3 000000c0 010 0102 0 ....L......

جیسا کہ نام سے پتہ چلتا ہے، block_upload_traffic.pcapng فائل PLC پر بلاک اپ لوڈ ٹریفک کا ایک ڈمپ پر مشتمل ہے۔

یہ بات قابل غور ہے کہ کانفرنس کے دوران مقابلے کی جگہ پر اس ٹریفک ڈمپ کو حاصل کرنا کچھ زیادہ مشکل تھا۔ ایسا کرنے کے لیے، TeslaSCADA2 کے لیے پروجیکٹ فائل سے اسکرپٹ کو سمجھنا ضروری تھا۔ اس سے یہ سمجھنا ممکن تھا کہ RC4 کا استعمال کرتے ہوئے خفیہ کردہ ڈمپ کہاں واقع تھا اور اسے ڈکرپٹ کرنے کے لیے کونسی کلید استعمال کرنے کی ضرورت ہے۔ S7 پروٹوکول کلائنٹ کا استعمال کرتے ہوئے سائٹ پر ڈیٹا بلاکس کے ڈمپ حاصل کیے جا سکتے ہیں۔ اس کے لیے میں نے Snap7 پیکیج سے ڈیمو کلائنٹ استعمال کیا۔

ٹریفک ڈمپ سے سگنل پروسیسنگ بلاکس نکالنا

ڈمپ کے مواد کو دیکھ کر، آپ سمجھ سکتے ہیں کہ اس میں سگنل پروسیسنگ بلاکس OB1، FC1، FC2 اور FC3 شامل ہیں:

انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 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 (pp) سے شروع ہوتے ہیں۔ اب آپ کو ان کا تجزیہ کرنے کا طریقہ سیکھنے کی ضرورت ہے۔ اسائنمنٹ کا اشارہ بتاتا ہے کہ آپ کو اس کے لیے PlcSim استعمال کرنے کی ضرورت ہے۔

بلاکس سے انسانی پڑھنے کے قابل ہدایات حاصل کرنا

سب سے پہلے، آئیے S7-PlcSim پروگرام کرنے کی کوشش کریں جس میں کئی بلاکس کو دہرانے والی ہدایات (= Q 0.0) کے ساتھ اس میں سمیٹک مینیجر سافٹ ویئر کا استعمال کرتے ہوئے لوڈ کریں، اور ایمولیٹر میں حاصل کردہ PLC کو example.plc فائل میں محفوظ کریں۔ فائل کے مواد کو دیکھ کر، آپ آسانی سے دستخط 70 70 کے ذریعہ ڈاؤن لوڈ کردہ بلاکس کی شروعات کا تعین کرسکتے ہیں، جو ہم نے پہلے دریافت کیا تھا۔ بلاکس سے پہلے، بظاہر، بلاک کا سائز 4 بائٹ لٹل اینڈین ویلیو کے طور پر لکھا جاتا ہے۔

انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 9 میں PLC کو کیسے ہیک کیا گیا

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)

الیکسی نے شاید زیادہ مشکل لیکن پھر بھی درست راستہ اختیار کیا۔ ہم نے فرض کیا کہ شرکاء NetToPlcSim پروگرام کا استعمال کریں گے تاکہ PlcSim نیٹ ورک پر بات چیت کر سکے، Snap7 کے ذریعے PlcSim پر بلاکس اپ لوڈ کر سکے، اور پھر ترقیاتی ماحول کا استعمال کرتے ہوئے PlcSim سے پروجیکٹ کے طور پر ان بلاکس کو ڈاؤن لوڈ کر سکے۔

نتیجے میں آنے والی فائل کو S7-PlcSim میں کھول کر، آپ سمیٹک مینیجر کا استعمال کرکے اوور رائٹ شدہ بلاکس کو پڑھ سکتے ہیں۔ اہم ڈیوائس کنٹرول کے افعال بلاک FC1 میں ریکارڈ کیے گئے ہیں۔ خاص طور پر نوٹ کریں #TEMP0 متغیر ہے، جو آن ہونے پر PLC کنٹرول کو M2.2 اور M2.3 بٹ میموری ویلیوز کی بنیاد پر مینوئل موڈ پر سیٹ کرتا دکھائی دیتا ہے۔ #TEMP0 ویلیو فنکشن FC3 کے ذریعے سیٹ کی گئی ہے۔

انڈسٹریل ننجا کے نقش قدم پر: مثبت ہیک دن 9 میں PLC کو کیسے ہیک کیا گیا

مسئلہ کو حل کرنے کے لیے، آپ کو FC3 فنکشن کا تجزیہ کرنے کی ضرورت ہے اور یہ سمجھنے کی ضرورت ہے کہ کیا کرنے کی ضرورت ہے تاکہ یہ ایک منطقی واپس آجائے۔

مقابلے کی جگہ پر لو سیکیورٹی اسٹینڈ پر PLC سگنل پروسیسنگ بلاکس کو اسی طرح ترتیب دیا گیا تھا، لیکن #TEMP0 متغیر کی قدر کو سیٹ کرنے کے لیے، DB1 بلاک میں میری ننجا کے راستے کو لکھنا کافی تھا۔ کسی بلاک میں قدر کی جانچ کرنا سیدھا سیدھا تھا اور اس کے لیے بلاک پروگرامنگ زبان کے گہرے علم کی ضرورت نہیں تھی۔ ظاہر ہے، ہائی سیکیورٹی کی سطح پر، دستی کنٹرول حاصل کرنا بہت زیادہ مشکل ہوگا اور STL زبان کی پیچیدگیوں کو سمجھنا ضروری ہے (S7 PLC کو پروگرام کرنے کا ایک طریقہ)۔

ریورس بلاک ایف سی 3

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 زبان کی تفصیلی ہدایات اور صلاحیتیں متعلقہ کتابچے میں دیکھی جا سکتی ہیں: 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 کنٹرول چالو ہو جاتا ہے اور غبارے کو پھٹنا یا پھٹنا ممکن ہو گا۔


بس! الیکسی نے ایک صنعتی ننجا کے لائق علم کی اعلیٰ سطح کا مظاہرہ کیا :) ہم نے فاتح کو یادگار انعامات بھیجے۔ تمام شرکاء کا بہت شکریہ!

ماخذ: www.habr.com

DDoS تحفظ، VPS VDS سرورز والی سائٹوں کے لیے قابل اعتماد ہوسٹنگ خریدیں۔ DDoS تحفظ، VPS VDS سرورز کے ساتھ قابل اعتماد ویب سائٹ ہوسٹنگ خریدیں۔ ProHoster