Setelah Industrial Ninja: bagaimana PLC diretas pada Positive Hack Days 9



Di PHDays 9, kami mengadakan kompetisi untuk meretas pabrik pompa gas - kontes Ninja Industri . Ada tiga stan di lokasi dengan berbagai parameter keselamatan (Tidak Ada Keamanan, Keamanan Rendah, Keamanan Tinggi) meniru proses industri yang sama: udara dipompa ke balon (dan kemudian turun) di bawah tekanan.

Terlepas dari berbagai parameter keamanan, perangkat keras dudukannya tetap sama: Siemens Simatic S7-300 PLC; tombol blow-off darurat dan alat pengukur tekanan (terhubung ke input digital PLC (DI)); katup untuk pemompaan dan pendarahan (terhubung ke output digital PLC (DO)) - lihat gambar di bawah ini.



PLC, tergantung pada pembacaan tekanan dan sesuai dengan programnya, membuat keputusan tentang meniup atau meniup bola (membuka dan menutup katup yang sesuai). Namun, mode kontrol manual disediakan di semua dudukan, yang memungkinkan untuk mengontrol kondisi katup tanpa batasan apa pun.

Stand dibedakan oleh kompleksitas memungkinkan mode ini: pada stand yang tidak terlindungi itu paling mudah dilakukan, tetapi pada stand High Security, karenanya, itu lebih sulit.

Dalam dua hari, lima dari enam masalah diselesaikan; pemenang tempat pertama mendapat 233 poin (dia menghabiskan satu minggu mempersiapkan kompetisi). Tiga pemenang: I place - a1exdandy, II - Rubikoid, III - Ze.

Namun, selama PHDays, tidak ada peserta yang mampu mengatasi ketiga tribun, jadi kami memutuskan untuk melakukan kontes online dan menerbitkan tugas yang paling sulit pada awal Juni. Peserta harus menyelesaikan tugas dalam sebulan, menemukan bendera, menjelaskan solusinya secara rinci dan menarik.

Di bawah potongan, kami menerbitkan analisis solusi terbaik untuk penugasan yang dikirim selama sebulan, ditemukan oleh Alexey Kovrizhnykh (a1exdandy) dari perusahaan Keamanan Digital, yang menempati posisi pertama dalam kompetisi selama PHDays. Di bawah ini kami berikan teksnya dengan komentar kami.

Analisis awal


Jadi, dalam tugas itu ada arsip dengan file:

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

File hints.txt berisi informasi dan tips yang diperlukan untuk menyelesaikan tugas. Berikut isinya:

  1. Petrovich memberi tahu saya kemarin bahwa dari PlcSim Anda dapat mengunduh blok di Step7.
  2. Di stan, Siemens Simatic S7-300 series PLC digunakan.
  3. PlcSim adalah emulator PLC yang memungkinkan Anda menjalankan dan men-debug program untuk Siemens S7 PLCs.

  File DB100.bin, tampaknya, berisi blok data 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 0206 0100 0103 0102 0a02 ..w .............
 00000030: 0501 0202 1602 0501 0206 0100 0104 0102 ................
 00000040: 7502 0401 0206 0100 0105 0102 0a02 0501 u ...............
 00000050: 0202 1602 0501 0206 0100 0106 0102 3402 .............. 4.
 00000060: 0401 0206 0100 0107 0102 2602 0501 0202 .......... & .....
 00000070: 4c02 0501 0206 0100 0108 0102 3302 0401 L ........... 3 ...
 00000080: 0206 0100 0109 0102 0a02 0501 0202 1602 ................
 00000090: 0501 0206 0100 010a 0102 3702 0401 0206 .......... 7 .....
 000000a0: 0100 010b 0102 2202 0501 0202 4602 0501 ...... "..... F ...
 000000b0: 0206 0100 010c 0102 3302 0401 0206 0100 ........ 3 .......
 000000c0: 010d 0102 0a02 0501 0202 1602 0501 0206 ................
 000000d0: 0100 010e 0102 6d02 0401 0206 0100 010f ...... m .........
 000000e0: 0102 1102 0501 0202 2302 0501 0206 0100 ........ # .......
 000000f0: 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 ..3 ........... &.
 00000120: 0501 0202 4c02 0501 0206 0100 .... L ....... 

Dilihat dari namanya, file block_upload_traffic.pcapng berisi dump lalu lintas pemuatan blok ke PLC.

Perlu dicatat bahwa tumpukan lalu lintas di situs kompetisi selama konferensi ini sedikit lebih sulit didapat. Untuk melakukan ini, perlu dipahami skrip dari file proyek untuk TeslaSCADA2. Dari situ dimungkinkan untuk memahami di mana dump yang dienkripsi dengan RC4 berada dan kunci mana yang harus digunakan untuk mendekripsi. Dump blok data di situs dapat diperoleh menggunakan klien protokol S7. Saya menggunakan klien demo dari paket Snap7 untuk ini.

Ekstraksi unit pemrosesan sinyal dari tempat pembuangan lalu lintas


Melihat isi dump, Anda dapat memahami bahwa blok pemrosesan sinyal OB1, FC1, FC2 dan FC3 ditransmisikan di dalamnya:



Diperlukan untuk mengekstrak blok ini. Ini dapat dilakukan, misalnya, dengan skrip berikut, setelah mengonversi lalu lintas dari format pcapng ke 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 ('\x1e\x00', '\x1e\x01'): # upload buf += s7_data[4:] elif s7_param == '\x1f': with open(next(names), 'wb') as f: f.write(buf) buf = '' 

Setelah mempelajari blok yang diterima, Anda dapat melihat bahwa mereka selalu dimulai dengan byte 70 70 (hal). Sekarang Anda perlu belajar cara menganalisisnya. Sebuah petunjuk untuk tugas tersebut menunjukkan bahwa Anda perlu menggunakan PlcSim untuk ini.

Mendapatkan instruksi yang bisa dibaca manusia dari blok


Pertama, mari kita coba program S7-PlcSim dengan memuat beberapa blok dengan instruksi berulang (= Q 0,0) ke dalamnya menggunakan perangkat lunak Simatic Manager, dan simpan hasilnya dalam emulator PLC dalam file example.plc. Dengan melihat isi file, Anda dapat dengan mudah menentukan awal blok yang dimuat dengan tanda tangan 70 70, yang kami temukan sebelumnya. Sebelum blok, tampaknya, ukuran blok ditulis dalam bentuk nilai bit-endian 4-byte.



Setelah kami menerima informasi tentang struktur file plc, rencana tindakan berikut muncul untuk membaca program PLC S7:

  1. Menggunakan Simatic Manager, kami membuat struktur blok di S7-PlcSim mirip dengan yang kami dapatkan dari dump. Ukuran blok harus sesuai (dicapai dengan mengisi blok dengan jumlah instruksi yang tepat) dan pengidentifikasi mereka (OB1, FC1, FC2, FC3).
  2. Simpan PLC ke file.
  3. Kami mengganti konten blok dalam file yang diterima dengan blok dari dump lalu lintas. Awal blok ditentukan oleh tanda tangan.
  4. File yang dihasilkan diunggah ke S7-PlcSim dan kami melihat isi blok di Simatic Manager.

Blok dapat diganti, misalnya, dengan kode berikut:

 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) 

Aleksey melanjutkan jalan yang mungkin lebih rumit, tetapi tetap dengan cara yang benar. Kami berasumsi bahwa peserta akan menggunakan program NetToPlcSim sehingga PlcSim dapat berkomunikasi melalui jaringan, memuat blok ke PlcSim melalui Snap7, dan kemudian mengunduh blok ini sebagai proyek dari PlcSim menggunakan lingkungan pengembangan.

Dengan membuka file yang dihasilkan di S7-PlcSim, Anda dapat membaca blok yang ditimpa menggunakan Simatic Manager. Fungsi manajemen perangkat utama dicatat di blok FC1. Variabel # TEMP0 menarik perhatian khusus, ketika dihidupkan, tampaknya kontrol PLC beralih ke mode manual berdasarkan nilai-nilai memori bit M2.2 dan M2.3. # TEMP0 diatur oleh FC3.



Untuk mengatasi masalah tersebut, perlu untuk menganalisis fungsi FC3 dan memahami apa yang perlu dilakukan sehingga mengembalikan unit logis.

Blok pemrosesan sinyal PLC di stand Keamanan Rendah di lokasi kompetisi diatur dengan cara yang sama, tetapi untuk menetapkan nilai variabel # TEMP0, cukup untuk menulis baris cara ninja saya ke blok DB1. Memeriksa nilai dalam blok diatur dengan jelas dan tidak memerlukan pengetahuan mendalam tentang bahasa pemrograman blok. Jelas, pada tingkat Keamanan Tinggi akan jauh lebih sulit untuk mencapai kontrol manual dan perlu untuk memahami seluk-beluk bahasa STL (salah satu cara pemrograman S7 PLC).

Membalikkan Blok FC3


Isi blok FC3 di representasi STL:
  LB#16#0 T #TEMP13 T #TEMP15 LP#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 LW#16#0 <>I JC M00d LP#DBX 0.0 LAR1 M00d: LB [AR1,P#0.0] T #TEMP5 LW#16#1 ==I JC M007 L #TEMP5 LW#16#2 ==I JC M008 L #TEMP5 LW#16#3 ==I JC M00f L #TEMP5 LW#16#4 ==I JC M00e L #TEMP5 LW#16#5 ==I JC M011 L #TEMP5 LW#16#6 ==I JC M012 JU M010 M007: +AR1 P#1.0 LP#DBX 0.0 LAR2 LB [AR1,P#0.0] LC#8 *I +AR2 +AR1 P#1.0 LB [AR1,P#0.0] JL M003 JU M001 JU M002 JU M004 M003: JU M005 M001: OPN DB 101 LB [AR2,P#0.0] T #TEMP0 JU M006 M002: OPN DB 101 LB [AR2,P#0.0] T #TEMP1 JU M006 M004: OPN DB 101 LB [AR2,P#0.0] T #TEMP2 JU M006 M00f: +AR1 P#1.0 LB [AR1,P#0.0] LC#8 *IT #TEMP11 +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP7 LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 TAR1 #TEMP4 OPN DB 101 LP#DBX 0.0 LAR1 L #TEMP11 +AR1 LAR2 #TEMP9 LB [AR2,P#0.0] TB [AR1,P#0.0] L #TEMP4 LAR1 JU M006 M008: +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP3 +AR1 P#1.0 LB [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 LB [AR1,P#0.0] T #TEMP7 LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 TAR1 #TEMP4 LAR1 #TEMP9 LAR2 #TEMP10 LB [AR1,P#0.0] LB [AR2,P#0.0] AW INVI T #TEMP12 LB [AR1,P#0.0] LB [AR2,P#0.0] OW L #TEMP12 AW TB [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 LB [AR1,P#0.0] T #TEMP7 LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 TAR1 #TEMP4 LAR1 #TEMP9 LAR2 #TEMP10 LB [AR1,P#0.0] LB [AR2,P#0.0] -ITB [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 LB [AR1,P#0.0] T #TEMP7 LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 TAR1 #TEMP4 LAR1 #TEMP9 LAR2 #TEMP10 LB [AR1,P#0.0] LB [AR2,P#0.0] ==I JCN M013 JU M014 M013: LP#DBX 0.0 LAR1 T #TEMP4 LB#16#0 T #TEMP6 JU M006 M014: L #TEMP4 LAR1 L #TEMP13 LL#1 +IT #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: LP#DBX 0.0 LAR1 L 0 T #TEMP6 TAR1 #TEMP4 M005: TAR1 #TEMP4 CLR = #TEMP16 L #TEMP13 LL#20 ==IS #TEMP16 L #TEMP15 ==IA #TEMP16 JC M017 L #TEMP13 LL#20 <IS #TEMP16 L #TEMP15 ==IA #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 

Kode ini cukup banyak dan bagi seseorang yang tidak terbiasa dengan STL, mungkin terlihat rumit. Tidak masuk akal untuk membongkar setiap instruksi dalam kerangka artikel ini, untuk instruksi terperinci dan fitur bahasa STL, lihat manual yang sesuai: Daftar Pernyataan (STL) untuk Pemrograman S7-300 dan S7-400 . Di sini saya akan memberikan kode yang sama setelah pemrosesan - mengganti nama label dan variabel dan menambahkan komentar yang menggambarkan algoritma kerja dan beberapa konstruksi bahasa STL. Saya langsung mencatat bahwa dalam blok yang dipertimbangkan mesin virtual diimplementasikan yang mengeksekusi beberapa bytecode yang terletak di blok DB100, yang isinya kita ketahui. Instruksi mesin virtual adalah 1 byte kode operasi dan byte argumen, satu byte untuk setiap argumen. Semua instruksi yang ditinjau memiliki dua argumen, saya menetapkan nilainya dalam komentar sebagai X dan Y.

Kode Pemrosesan Posting
]
 #    LB#16#0 T #CHECK_N #     T #COUNTER_N #     LP#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 LW#16#0 <>I JC M00d LP#DBX 0.0 LAR1 #  switch - case     M00d: LB [AR1,P#0.0] T #OPCODE LW#16#1 ==I JC OPCODE_1 L #OPCODE LW#16#2 ==I JC OPCODE_2 L #OPCODE LW#16#3 ==I JC OPCODE_3 L #OPCODE LW#16#4 ==I JC OPCODE_4 L #OPCODE LW#16#5 ==I JC OPCODE_5 L #OPCODE LW#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 LP#DBX 0.0 LAR2 LB [AR1,P#0.0] #   X (  DB101) LC#8 *I +AR2 +AR1 P#1.0 LB [AR1,P#0.0] #   Y ( ) JL M003 #  switch - case    Y JU M001 #      . JU M002 #       JU M004 #      M003: JU LOOPEND M001: OPN DB 101 LB [AR2,P#0.0] T #REG0 #   DB101[X]  REG[0] JU PRE_LOOPEND M002: OPN DB 101 LB [AR2,P#0.0] T #REG1 #   DB101[X]  REG[1] JU PRE_LOOPEND M004: OPN DB 101 LB [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 LB [AR1,P#0.0] T #TEMP3 +AR1 P#1.0 LB [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 LB [AR1,P#0.0] T #TEMP7 #   - X LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 # REG[X] +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 # REG[Y] TAR1 #POINTER LAR1 #TEMP9 # REG[X] LAR2 #TEMP10 # REG[Y] LB [AR1,P#0.0] LB [AR2,P#0.0] AW INVI T #TEMP12 # ~(REG[Y] & REG[X]) LB [AR1,P#0.0] LB [AR2,P#0.0] OW L #TEMP12 AW # (~(REG[Y] & REG[X])) & (REG[Y] | REG[X]) -     TB [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 LB [AR1,P#0.0] T #TEMP7 LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 # REG[X] +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 # REG[Y] TAR1 #POINTER LAR1 #TEMP9 LAR2 #TEMP10 LB [AR1,P#0.0] LB [AR2,P#0.0] -I # ACCU1 = ACCU2 - ACCU1, REG[X] - REG[Y] TB [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 LB [AR1,P#0.0] T #TEMP7 # REG[X] LP#M 100.0 LAR2 L #TEMP7 LC#8 *I +AR2 TAR2 #TEMP9 # REG[X] +AR1 P#1.0 LB [AR1,P#0.0] T #TEMP8 LP#M 100.0 LAR2 L #TEMP8 LC#8 *I +AR2 TAR2 #TEMP10 # REG[Y] TAR1 #POINTER LAR1 #TEMP9 # REG[Y] LAR2 #TEMP10 # REG[X] LB [AR1,P#0.0] LB [AR2,P#0.0] ==I JCN M013 JU M014 M013: LP#DBX 0.0 LAR1 T #POINTER LB#16#0 T #TEMP6 JU PRE_LOOPEND M014: L #POINTER LAR1 #   #CHECK_N L #CHECK_N LL#1 +IT #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: LP#DBX 0.0 LAR1 L 0 T #TEMP6 TAR1 #POINTER LOOPEND: TAR1 #POINTER CLR = #TEMP16 L #CHECK_N LL#20 ==IS #TEMP16 L #COUNTER_N ==IA #TEMP16 #   ,  #CHECK_N == #COUNTER_N == 20 JC GOOD L #CHECK_N LL#20 <IS #TEMP16 L #COUNTER_N ==IA #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 

Setelah mendapat gagasan tentang instruksi mesin virtual, kami akan menulis disassembler kecil untuk mem-parsing bytecode di blok 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 

Hasilnya, kami mendapatkan kode mesin virtual berikut:

Kode mesin virtual
 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) 

Seperti yang Anda lihat, program ini hanya memeriksa setiap simbol dari DB101 untuk kesetaraan ke nilai tertentu. Baris terakhir untuk melewati semua pemeriksaan: n0w u 4r3 7h3 m4573r. Jika garis ini ditempatkan di blok DB101, kontrol manual dari PLC diaktifkan dan akan mungkin untuk meledakkan atau mengempiskan balon.

Itu saja! Alexey mendemonstrasikan pengetahuan tingkat tinggi yang layak untuk seorang ninja industri :) Kami mengirimkan hadiah yang tak terlupakan kepada pemenang. Terima kasih banyak untuk semua peserta!

Source: https://habr.com/ru/post/id460615/


All Articles