In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

Ag an PHDays deiridh 9 bhí comórtas againn chun gléasra pumpála gáis a hack - comórtas Cluiche Ninja Tionscail. Bhí trí sheastán ar an suíomh le paraiméadair slándála éagsúla (Gan Slándáil, Slándáil Íseal, Ard-Slándáil), ag déanamh aithrise ar an bpróiseas tionsclaíoch céanna: rinneadh aer faoi bhrú a phumpáil isteach i mbalún (agus ansin scaoileadh).

In ainneoin na paraiméadair sábháilteachta éagsúla, bhí comhdhéanamh crua-earraí na seastáin mar an gcéanna: sraith Siemens Simatic PLC S7-300; cnaipe díbhoilscithe éigeandála agus feiste tomhais brú (ceangailte le hionchuir dhigiteacha PLC (DI)); comhlaí ag feidhmiú le haghaidh boilscithe agus díbhoilsciú aeir (ceangailte le haschuir dhigiteacha an PLC (DO)) - féach an figiúr thíos.

In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

Rinne an PLC, ag brath ar na léamha brú agus de réir a chláir, cinneadh an liathróid a dhíbhoilsciú nó a inflate (d'oscail agus dhún sé na comhlaí comhfhreagracha). Mar sin féin, bhí modh rialaithe láimhe ag gach seastán, rud a d'fhág gur féidir staid na comhla a rialú gan aon srianta.

Bhí difríocht idir na seastáin maidir leis an gcastacht a bhain leis an modh seo a chumasú: ag an seastán gan chosaint bhí sé níos éasca é seo a dhéanamh, agus ag an seastán Ard-Slándála bhí sé níos deacra dá réir.

Réitíodh cúig cinn de na sé fhadhb i dhá lá; Ghnóthaigh rannpháirtí an chéad áit 233 pointe (chaith sé seachtain ag ullmhú don chomórtas). Trí buaiteoirí: áitím - a1exdandy, II - Rubikoid, III - Ze.

Mar sin féin, le linn PHDays, ní raibh aon cheann de na rannpháirtithe in ann na trí sheastán a shárú, mar sin shocraigh muid a dhéanamh ar chomórtas ar líne agus d'fhoilsigh an tasc is deacra go luath i mí an Mheithimh. Bhí ar na rannpháirtithe an tasc a chríochnú laistigh de mhí, an bhratach a aimsiú, agus cur síos a dhéanamh ar an réiteach go mion agus ar bhealach suimiúil.

Faoi bhun an ghearrtha foilsímid anailís ar an réiteach is fearr ar an tasc uathu siúd a seoladh thar na míosa, fuair Alexey Kovrizhnykh (a1exdandy) ón gcuideachta Slándála Digiteach, a ghlac an XNUMXú áit sa chomórtas le linn PHDays é. Anseo thíos cuirimid a téacs i láthair lenár dtuairimí.

Anailís tosaigh

Mar sin, bhí cartlann leis na comhaid seo a leanas sa tasc:

  • block_upload_traffic.pcapng
  • DB100.bin
  • leideanna.txt

Tá an fhaisnéis agus na leideanna riachtanacha sa chomhad hints.txt chun an tasc a réiteach. Seo a bhfuil ann:

  1. Dúirt Petrovich liom inné gur féidir leat bloic a luchtú ó PlcSim isteach i gCéim 7.
  2. Baineadh úsáid as an tsraith Siemens Simatic S7-300 PLC ag an seastán.
  3. Is aithriseoir PLC é PlcSim a ligeann duit cláir a rith agus a dhífhabhtú do Siemens S7 PLC.

Is cosúil go bhfuil an bloc sonraí DB100 PLC sa chomhad DB100.bin: 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 0103a0102 ..w........... 0: 02 00000030 0501 0202 1602 0501 ...... 0206 0100............0104. 0102: 00000040 7502 0401 0206 0100 0105 0102 0 .........&.... 02: 0501c00000050 0202 1602 0501 0206 0100 0106 : 0102 3402 4 00000060 0401a0206 0100 0107 0102 ................ 2602: 0501 0202 00000070 4a 02 0501 0206 0100 ............ 0108a0102: 3302 0401b 3 00000080 0206 0100 0109 0102 ......".....F... 0b02: 0501 0202 1602c 00000090 0501...".....F... 0206b0100: 010 0102 3702c 0401 0206..." .. 7c000000: 0d 0100 010a0102 2202 0501 0202 4602 0501................ 000000d0: 0206 0100e 010 0102d3302 0401 0206 ... . .... 0100e3: 000000 0 010 0102 0 02 0501 0202 ........#...... 1602f0501: 0206 000000 0 0100 010 0102 ... . ..... 6: 02 0401 0206 0100 010 000000 0 0102 ...... %......... 1102: 0501 0202 2302 0501 0206 0100 ... . ....&. 000000: 0 0110 0102c3502 0401 0206 0100 ....L......

Mar a thugann an t-ainm le fios, tá dumpáil tráchta blocuaslódála chuig an PLC sa chomhad block_upload_traffic.pcapng.

Is fiú a thabhairt faoi deara go raibh an dumpáil tráchta seo ag láithreán an chomórtais le linn na comhdhála beagán níos deacra a fháil. Chun seo a dhéanamh, bhí sé riachtanach an script ón gcomhad tionscadail do TeslaSCADA2 a thuiscint. Bhíothas in ann a thuiscint cá háit a raibh an dumpáil criptithe ag baint úsáide as RC4 suite agus cén eochair ba ghá a úsáid chun é a dhíchriptiú. D’fhéadfaí dumpaí de bhloic sonraí ar an suíomh a fháil trí úsáid a bhaint as an gcliant prótacail S7. Chun seo a úsáid mé an cliant taispeána ón bpacáiste Snap7.

Bloic próiseála comhartha a bhaint as dumpáil tráchta

Ag féachaint ar a bhfuil sa dumpáil, is féidir leat a thuiscint go bhfuil bloic próiseála comhartha OB1, FC1, FC2 agus FC3 ann:

In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

Ní mór na bloic seo a bhaint. Is féidir é seo a dhéanamh, mar shampla, leis an script seo a leanas, tar éis an trácht a thiontú ón bhformáid pcapng go pcap roimhe seo:

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

Tar éis duit na bloic mar thoradh air sin a scrúdú, tabharfaidh tú faoi deara go dtosaíonn siad i gcónaí le bearta 70 70 (pp). Anois ní mór duit a fháil amach conas anailís a dhéanamh orthu. Tugann leid an taisc le fios go gcaithfidh tú PlcSim a úsáid chuige seo.

Treoracha inléite daonna a fháil ó bhloic

Ar dtús, déanaimis iarracht S7-PlcSim a ríomh trí roinnt bloic a luchtú le treoracha athrá (= Q 0.0) isteach ann ag baint úsáide as bogearraí Bainisteoir Simatic, agus an PLC a fhaightear san aithriseoir a shábháil chuig an gcomhad example.plc. Trí bhreathnú ar ábhar an chomhaid, is féidir leat tús na mbloic íoslódála a chinneadh go héasca leis an síniú 70 70, a fuair muid amach níos luaithe. Roimh na bloic, is cosúil, tá an méid bloc scríofa mar luach beag-deireadh 4-beart.

In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

Tar éis dúinn faisnéis a fháil faoi struchtúr na gcomhad cpt, tháinig an plean gníomhaíochta seo a leanas chun solais maidir le cláir PLC S7 a léamh:

  1. Ag baint úsáide as Simatic Manager, cruthaímid struchtúr bloc i S7-PlcSim cosúil leis an gceann a fuair muid ón dumpáil. Ní mór méideanna na mbloc a mheaitseáil (baintear é seo amach trí na bloic a líonadh leis an líon riachtanach treoracha) agus a n-aitheantóirí (OB1, FC1, FC2, FC3).
  2. Sábháil an PLC i gcomhad.
  3. Déanaimid na bloic ón dumpáil tráchta a chur in ionad ábhar na mbloic sa chomhad mar thoradh air. Is é an síniú a chinnfidh tús na mbloic.
  4. Déanaimid an comhad mar thoradh air a luchtú isteach i S7-PlcSim agus féachaimid ar a bhfuil sna bloic i Simatic Manager.

Is féidir an cód seo a leanas a chur in ionad bloic, mar shampla:

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)

Ghlac Alexey cosán b'fhéidir níos deacra, ach fós ceart. Ghlacamar leis go n-úsáidfeadh rannpháirtithe an clár NetToPlcSim ionas go bhféadfadh PlcSim cumarsáid a dhéanamh thar an líonra, bloic a uaslódáil chuig PlcSim trí Snap7, agus ansin na bloic seo a íoslódáil mar thionscadal ó PlcSim ag baint úsáide as an timpeallacht forbartha.

Tríd an gcomhad mar thoradh air a oscailt in S7-PlcSim, is féidir leat na bloic fhorscríofa a léamh ag baint úsáide as an mBainisteoir Simatic. Déantar príomhfheidhmeanna rialaithe an fheiste a thaifeadadh i bloc FC1. Is díol suntais ar leith an athróg #TEMP0, agus nuair a chuirtear ar siúl é is cosúil go socraíonn sé an rialú PLC go mód láimhe bunaithe ar luachanna cuimhne giotán M2.2 agus M2.3. Tá an luach #TEMP0 socraithe ag feidhm FC3.

In the footsteps of Industrial Ninja: how a PLC was hacked at Positive Hack Days 9

Chun an fhadhb a réiteach, ní mór duit anailís a dhéanamh ar fheidhm FC3 agus tuiscint a fháil ar cad is gá a dhéanamh ionas go dtiocfaidh sé ar ais ar cheann loighciúil.

Socraíodh na bloic próiseála comhartha PLC ag an seastán Slándála Íseal ag an suíomh comórtais ar bhealach comhchosúil, ach chun luach an athróg #TEMP0 a shocrú, bhí sé go leor chun an líne mo bhealach ninja a scríobh isteach sa bhloc DB1. Bhí sé simplí an luach i mbloc a sheiceáil agus ní raibh gá le heolas domhain ar theanga ríomhchlárúcháin na mbloc. Ar ndóigh, ag an leibhéal Ard-Slándála, beidh sé i bhfad níos deacra rialú láimhe a bhaint amach agus is gá tuiscint a fháil ar intricacies na teanga STL (ceann de na bealaí chun an S7 PLC a ríomh).

Bloc droim ar ais FC3

Ábhar an bhloc FC3 i léiriú 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

Tá an cód sách fada agus d’fhéadfadh cuma casta air ag duine nach bhfuil cur amach aige ar STL. Níl aon chiall le hanailís a dhéanamh ar gach treoir faoi chuimsiú an ailt seo; tá treoracha mionsonraithe agus cumais na teanga STL le fáil sa lámhleabhar comhfhreagrach: Liosta Ráitis (STL) do Chlárú S7-300 agus S7-400. Anseo cuirfidh mé an cód céanna i láthair tar éis próiseála - ag athainmniú na lipéid agus na n-athróg agus ag cur tuairimí leis ag cur síos ar algartam na hoibríochta agus roinnt tógálacha teanga STL. Tabhair faoi deara láithreach go bhfuil meaisín fíorúil sa bhloc atá i gceist a fhorghníomhaíonn roinnt bytecode atá suite sa bhloc DB100, a bhfuil a fhios againn a bhfuil ann. Tá treoracha meaisín fíorúil comhdhéanta de bheart amháin de chód oibriúcháin agus beart argóintí, beart amháin do gach argóint. Tá dhá argóint ag gach treoir mheas; d'ainmnigh mé a luachanna sna tuairimí mar X agus Y.

Cód tar éis próiseála]

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

Tar éis smaoineamh a fháil ar threoracha an mheaisín fhíorúil, scríobhaimis díchumadóir beag chun an bytecode a pharsáil sa 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 sin, faigheann muid an cód meaisín fíorúil seo a leanas:

Cóid meaisín fíorúil

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 fheiceann tú, ní dhéanann an clár seo ach seiceáil ar gach carachtar ó DB101 le haghaidh comhionannais go luach áirithe. Is í an líne dheireanach chun gach seiceáil a rith ná: n0w u 4r3 7h3 m4573r. Má chuirtear an líne seo i mbloc DB101, ansin cuirtear rialú láimhe PLC i ngníomh agus beifear in ann an balún a phléascadh nó a dhíbhoilsciú.


Sin é an méid! Léirigh Alexey leibhéal ard eolais ar fiú ninja tionsclaíochta :) Chuireamar duaiseanna cuimhneacha chuig an mbuaiteoir. Míle buíochas do na rannpháirtithe ar fad!

Foinse: will.com

Ceannaigh óstáil iontaofa do shuímh le cosaint DDoS, freastalaithe VPS VDS 🔥 Ceannaigh óstáil gréasáin iontaofa le cosaint DDoS, freastalaithe VPS VDS | ProHoster