Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Aig na làithean PHDays 9 mu dheireadh chùm sinn farpais gus ionad pumpaidh gas a sheacadh - farpais Ninja gnìomhachais. Bha trì seataichean air an làrach le diofar pharaimearan tèarainteachd (Gun Tèarainteachd, Tèarainteachd Ìosal, Tèarainteachd Àrd), a’ dèanamh atharrais air an aon phròiseas gnìomhachais: chaidh èadhar fo chuideam a phumpadh a-steach do bhalùn (agus an uairsin a leigeil ma sgaoil).

A dh 'aindeoin na diofar pharaimearan sàbhailteachd, bha co-dhèanamh bathar-cruaidh nan seasamh mar an ceudna: sreath Siemens Simatic PLC S7-300; putan dìon èiginn agus inneal tomhais cuideam (ceangailte ri cuir a-steach didseatach PLC (DI)); bhalbhaichean ag obair airson atmhorachd agus deflation adhair (ceangailte ri toraidhean didseatach PLC (DO)) - faic am figear gu h-ìosal.

Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Rinn an PLC, a rèir na leughaidhean cuideam agus a rèir a phrògram, co-dhùnadh am ball a spreadhadh no a thoirt a-steach (dh’ fhosgail agus dhùin e na bhalbhaichean co-fhreagarrach). Ach, bha modh smachd làimhe aig a h-uile ionad, a rinn e comasach smachd a chumail air staid nam bhalbhaichean gun bhacadh sam bith.

Bha na standan eadar-dhealaichte ann an iom-fhillteachd a bhith a’ comasachadh a’ mhodh seo: aig an ionad gun dìon bha e na b’ fhasa seo a dhèanamh, agus aig an ionad tèarainteachd àrd bha e na bu duilghe.

Chaidh còig de na sia duilgheadasan fhuasgladh ann an dà latha; Choisinn a 'chiad chom-pàirtiche 233 puingean (chuir e seachad seachdain ag ullachadh airson a' cho-fharpais). Trì buannaichean: I place - a1exdandy, II - Rubikoid, III - Ze.

Ach, rè PHDays, cha robh e comasach dha gin de na com-pàirtichean faighinn thairis air na trì seataichean, agus mar sin chuir sinn romhainn farpais air-loidhne a dhèanamh agus dh’ fhoillsich sinn an obair as duilghe tràth san Ògmhios. Dh'fheumadh com-pàirtichean an obair a chrìochnachadh taobh a-staigh mìos, lorg a 'bhratach, agus cunntas a thoirt air an fhuasgladh gu mionaideach agus ann an dòigh inntinneach.

Fon gearradh bidh sinn a’ foillseachadh mion-sgrùdadh air an fhuasgladh as fheàrr air a’ ghnìomh bhon fheadhainn a chaidh a chuir a-steach thairis air a’ mhìos, chaidh a lorg le Alexey Kovrizhnykh (a1exdandy) bhon chompanaidh Tèarainteachd Didseatach, a ghabh àite XNUMXd anns a’ cho-fharpais rè PhDays. Gu h-ìosal tha sinn a’ taisbeanadh an teacsa aige leis na beachdan againn.

Mion-sgrùdadh tùsail

Mar sin, bha tasglann anns an obair leis na faidhlichean a leanas:

  • block_upload_traffic.pcapng
  • DB100.bin
  • sanasan.txt

Anns an fhaidhle hints.txt tha am fiosrachadh riatanach agus sanasan gus an obair fhuasgladh. Seo na tha ann:

  1. Dh'innis Petrovich dhomh an-dè gun urrainn dhut blocaichean a luchdachadh bho PlcSim gu Step7.
  2. Chaidh an t-sreath Siemens Simatic S7-300 PLC a chleachdadh aig an ionad.
  3. Tha PlcSim na emuladair PLC a leigeas leat prògraman a ruith agus dì-bhugachadh airson Siemens S7 PLCs.

Tha e coltach gu bheil am faidhle DB100.bin a’ toirt a-steach bloc dàta 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 0100a0103 ..w............. 0102: 0 02 00000030 0501 0202 1602 ................ 0501: 0206 0100 0104 0102 00000040 7502 0401a0206 0100 u............... 0105: 0102 0 02 0501 00000050 0202 1602 0501............0206. 0100: 0106 0102 3402 4 00000060 0401 0206 0100 .........&..... 0107: 0102c2602 0501 0202 00000070 4 02 0501 0206 .......... : 0100 0108 0102 3302 0401a3 00000080 0206 0100 ................ 0109: 0102 0 02 0501a 0202 1602 00000090 0501 ............ 0206a0100: 010 0102b 3702 0401 0206 7 000000 0 ......".....F... 0100b010: 0102 2202 0501c 0202 4602 ..0501 ... .. 000000c0: 0206d 0100 010a0102 3302 0401 0206 0100 3 ................ 000000d0: 010 0102e 0 02d0501 0202 1602 ... .f .... 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 0202c2502 0501 0206 0100 ....L.....

Mar a tha an t-ainm a’ moladh, anns an fhaidhle block_upload_traffic.pcapng tha cnap de thrafaig luchdachadh suas bloca chun PLC.

Is fhiach a bhith mothachail gu robh an dump trafaic seo aig làrach na farpais rè na co-labhairt beagan na bu duilghe fhaighinn. Gus seo a dhèanamh, bha e riatanach an sgriobt a thuigsinn bhon fhaidhle pròiseict airson TeslaSCADA2. Bhon sin bha e comasach tuigsinn far an robh an dump a chaidh a chrioptachadh le bhith a’ cleachdadh RC4 suidhichte agus dè an iuchair a dh’ fheumar a chleachdadh gus a dhì-chrioptachadh. Gheibheadh ​​​​dumpaichean de bhlocaichean dàta air an làrach a’ cleachdadh teachdaiche protocol S7. Airson seo chleachd mi an neach-dèiligidh demo bhon phasgan Snap7.

A’ toirt a-mach blocaichean giollachd chomharran bho dump trafaic

A’ coimhead air susbaint an dump, tuigidh tu gu bheil blocaichean giollachd chomharran OB1, FC1, FC2 agus FC3 ann:

Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Feumar na blocaichean sin a thoirt air falbh. Faodar seo a dhèanamh, mar eisimpleir, leis an sgriobt a leanas, an dèidh dhut an trafaic atharrachadh bhon chruth pcapng gu pcap roimhe:

#!/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 = ''

An dèidh sgrùdadh a dhèanamh air na blocaichean a thig às, chì thu gu bheil iad an-còmhnaidh a’ tòiseachadh le bytes 70 70 (pp). A-nis feumaidh tu ionnsachadh mar a nì thu mion-sgrùdadh orra. Tha an sanas sònrachaidh a’ moladh gum feum thu PlcSim a chleachdadh airson seo.

Faigh stiùireadh a ghabhas leughadh le daoine bho bhlocaichean

An toiseach, feuchaidh sinn ri S7-PlcSim a phrògramadh le bhith a’ luchdachadh grunn bhlocaichean le stiùireadh ath-aithris (= Q 0.0) a-steach ann a’ cleachdadh bathar-bog Simatic Manager, agus a’ sàbhaladh an PLC a gheibhear san emuladair don fhaidhle example.plc. Le bhith a’ coimhead air susbaint an fhaidhle, is urrainn dhut gu furasta toiseach nam blocaichean a chaidh a luchdachadh sìos a dhearbhadh leis an ainm-sgrìobhte 70 70, a lorg sinn na bu thràithe. Ro na blocaichean, a rèir coltais, tha meud a 'bhloc air a sgrìobhadh mar luach beag-endian 4-byte.

Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Às deidh dhuinn fiosrachadh fhaighinn mu structar faidhlichean plc, nochd am plana gnìomh a leanas airson prògraman PLC S7 a leughadh:

  1. A 'cleachdadh Simatic Manager, bidh sinn a' cruthachadh structar bloc ann an S7-PlcSim coltach ris an fhear a fhuair sinn bhon dump. Feumaidh meud nam blocaichean a bhith co-ionnan (tha seo air a choileanadh le bhith a 'lìonadh nam blocaichean leis an àireamh riatanach de stiùiridhean) agus an aithnichearan (OB1, FC1, FC2, FC3).
  2. Sàbhail am PLC gu faidhle.
  3. Cuiridh sinn na blocaichean bhon dump trafaic an àite susbaint nam blocaichean san fhaidhle a thig às. Tha toiseach nam blocaichean air a dhearbhadh leis an ainm-sgrìobhte.
  4. Bidh sinn a’ luchdachadh am faidhle a thig às a-steach gu S7-PlcSim agus a’ coimhead air susbaint nam blocaichean ann an Simatic Manager.

Faodar blocaichean a chuir an àite, mar eisimpleir, leis a’ chòd a leanas:

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)

Ghabh Alexei slighe is dòcha nas duilghe, ach fhathast ceart. Ghabh sinn ris gun cleachdadh com-pàirtichean am prògram NetToPlcSim gus am b’ urrainn dha PlcSim conaltradh thairis air an lìonra, blocaichean a luchdachadh suas gu PlcSim tro Snap7, agus an uairsin na blocaichean sin a luchdachadh sìos mar phròiseact bho PlcSim a’ cleachdadh na h-àrainneachd leasachaidh.

Le bhith a’ fosgladh am faidhle a thig às ann an S7-PlcSim, faodaidh tu na blocaichean ath-sgrìobhte a leughadh a’ cleachdadh an Simatic Manager. Tha na prìomh ghnìomhan smachd inneal air an clàradh ann am bloc FC1. Gu sònraichte cudromach tha an caochladair #TEMP0, a tha, nuair a thèid a thionndadh air, a rèir coltais a’ suidheachadh smachd PLC gu modh làimhe stèidhichte air luachan cuimhne bit M2.2 agus M2.3. Tha an luach #TEMP0 air a shuidheachadh le gnìomh FC3.

Ann an ceumannan Industrial Ninja: mar a chaidh PLC a slaodadh aig Positive Hack Days 9

Gus an duilgheadas fhuasgladh, feumaidh tu gnìomh FC3 a sgrùdadh agus tuigsinn dè a dh’ fheumar a dhèanamh gus am bi e loidsigeach air ais.

Chaidh na blocaichean giullachd chomharran PLC aig an ionad Tèarainteachd Ìosal aig làrach na farpais a chuir air dòigh san aon dòigh, ach gus luach an caochladair #TEMP0 a shuidheachadh, bha e gu leòr an loidhne mo shlighe ninja a sgrìobhadh a-steach don bhloc DB1. Bha e furasta a bhith a’ sgrùdadh an luach ann am bloc agus cha robh feum air eòlas domhainn air cànan prògramadh a’ bhloc. Gu dearbh, aig ìre Tèarainteachd Àrd, bidh e tòrr nas duilghe smachd làimhe a choileanadh agus feumar tuigse fhaighinn air iom-fhillteachd cànan STL (aon de na dòighean air an S7 PLC a phrògramadh).

Bloc air ais FC3

Susbaint a’ bhloc FC3 ann an riochdachadh STL:

      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

Tha an còd gu math fada agus dh’ fhaodadh gum bi e toinnte do chuideigin air nach eil eòlas air STL. Chan eil feum ann mion-sgrùdadh a dhèanamh air gach stiùireadh taobh a-staigh frèam an artaigil seo; gheibhear stiùireadh mionaideach agus comasan cànan STL anns an leabhar-làimhe co-fhreagarrach: Liosta Aithris (STL) airson Prògramadh S7-300 agus S7-400. An seo nochdaidh mi an aon chòd às deidh a ghiullachd - ag ath-ainmeachadh na bileagan agus na caochladairean agus a’ cur bheachdan a-steach a ’toirt cunntas air an algairim obrachaidh agus cuid de structaran cànain STL. Leig dhomh a thoirt fa-near sa bhad gu bheil inneal brìgheil anns a ’bhloc sin a bhios a’ cur an gnìomh cuid de bytecode a tha suidhichte anns a ’bhloc DB100, air a bheil sinn eòlach air na tha ann. Tha stiùireadh inneal mas-fhìor a’ toirt a-steach 1 byte de chòd obrachaidh agus bytes argamaidean, aon byte airson gach argamaid. Tha dà argamaid aig a h-uile stiùireadh beachdaichte; Chomharraich mi na luachan aca anns na beachdan mar X agus Y.

Còd an dèidh giollachd]

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

Às deidh dhuinn beachd fhaighinn air an stiùireadh inneal brìgheil, sgrìobhamaid disassembler beag gus am bytecode a pharsadh anns a’ bhloc 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

Mar thoradh air an sin, gheibh sinn an còd inneal brìgheil a leanas:

Còd mas-fhìor machine

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)

Mar a chì thu, tha am prògram seo dìreach a’ sgrùdadh gach caractar bho DB101 airson co-ionannachd gu luach sònraichte. Is e an loidhne mu dheireadh airson a bhith a’ dol seachad air a h-uile seic: n0w u 4r3 7h3 m4573r. Ma thèid an loidhne seo a chuir ann am bloc DB101, thèid smachd làimhe PLC a chuir an gnìomh agus bidh e comasach am bailiùn a spreadhadh no a spreadhadh.


Sin e! Sheall Alexey ìre àrd de eòlas a bha airidh air ninja gnìomhachais :) Chuir sinn duaisean cuimhneachail chun bhuannaiche. Mòran taing dha na com-pàirtichean uile!

Source: www.habr.com

Cuir beachd ann