Постановка задачи

Есть устройство, работает с чипами ss02-1, умеет в них писать и читать. Для этого в себе содержит алгоритмы генерации паролей на авторизацию и запись, мы хотим разобрать алгоритм и написать код, который будет выдавать тот же результат.

Что имеем - прошивку устройства, серийный номер чипа, на основание которого генерируются пароли. Устройство xerox wc 4250, прошивка у меня в наличии версии 15.003.70.000.

Выбор инструментов

  • На первом месте Ida. Интерактивный дизассемблер, инструмент для анализа кода, загрузим прошивку, восстановим порядок генерации, определим какие функции что делают, построим первоначальный каркас будущей программы.

  • TRACE32 Arm Debugger от lauterbach. Откровенно говоря, у меня старая версия, в about написано Release Jun 2011. Возможно сейчас есть и другие инструменты, но и этот отлично справляется с задачей. В нем можно создать виртуальную среду, выбрать тип эмулируемого процессора, загрузить прошивку, запустить на выполнение и получить результат. Можно выполнять пошагово сверяясь со своим кодом, искать ошибки.

  • Python - тут пишем код.

Первый взгляд

Для начала нужно достать из прошивки ядро, оно после сигнатуры “$ZIP”, начиная с 0x78 0x9C - zip архив. Пишем код:

import zlib
def read_u32(tab, addr):
    res = tab[addr]
    res = res << 8 | tab[addr+1]
    res = res << 8 | tab[addr+2]
    res = res << 8 | tab[addr+3]
    return res
with open("WC4250_15.003.70.000.hd", 'rb') as f:
    data = f.read()
pos = 0

while True:
    pos = data.find(b"$ZIP", pos)
    if pos == -1:
        break
    filename_bytes = data[pos + 4:pos + 8]
    filename_hex = filename_bytes.hex().upper()
    block_size = read_u32(data,8) 
    block_start = pos + 12
    compressed_data = data[block_start:block_start + block_size]
    if compressed_data[:2] == b'\x78\x9C':
        filename = f"{filename_hex}.bin"
        decompressed_data = zlib.decompress(compressed_data)
        with open(filename, 'wb') as f:
            f.write(decompressed_data)
        pos += 12 + block_size
    else:
        pos += 1

Грузим в ida, ищем нужную процедурку. Пропускаю подробности, т.к. задачка в алгоритме, на нем подробнее.

Под спойлером функция sub_203D548. Судя по строковым константам INSTALL_TONER, CHIPv1.0…Invalid, INVALID_TONER то что нужно.

Листинг функции sub_203D548 как есть
ROM:0203D548 sub_203D548                             ; CODE XREF: sub_1D848C4+34p
ROM:0203D548                                         ; sub_1D84CA8+4p
ROM:0203D548
ROM:0203D548 var_64          = -0x64
ROM:0203D548 var_5C          = -0x5C
ROM:0203D548 var_54          = -0x54
ROM:0203D548 var_48          = -0x48
ROM:0203D548 var_40          = -0x40
ROM:0203D548 var_30          = -0x30
ROM:0203D548 var_1C          = -0x1C
ROM:0203D548 var_16          = -0x16
ROM:0203D548 var_15          = -0x15
ROM:0203D548 var_14          = -0x14
ROM:0203D548 var_E           = -0xE
ROM:0203D548 var_D           = -0xD
ROM:0203D548
ROM:0203D548                 STMFD   SP!, {R4,R5,LR}
ROM:0203D54C                 SUB     SP, SP, #0x60	
ROM:0203D550                 ADD     R0, SP, #0x50	
ROM:0203D554                 MOV     R1, #0
ROM:0203D558                 MOV     R2, #0
ROM:0203D55C                 MOV     R3, #0
ROM:0203D560                 MOV     R4, #0
ROM:0203D564                 STMIA   R0, {R1-R4}	 
ROM:0203D568                 ADD     R0, SP, #0x2C
ROM:0203D56C                 MOV     R1, #0
ROM:0203D570                 MOV     R2, #0
ROM:0203D574                 MOV     R4, #0
ROM:0203D578                 MOV     R3, #0
ROM:0203D57C                 STMIA   R0, {R1-R4}
ROM:0203D580                 ADD     R0, SP, #0x24
ROM:0203D584                 MOV     R1, #0
ROM:0203D588                 MOV     R2, #0
ROM:0203D58C                 STMIA   R0, {R1,R2}
ROM:0203D590                 LDR     R4, =0x28A7708
ROM:0203D594                 LDRB    R0, [R4]
ROM:0203D598                 MOV     R1, R0,LSL#4
ROM:0203D59C                 LDR     R0, =dword_224A6B0
ROM:0203D5A0                 STRB    R1, [R0]
ROM:0203D5A4                 BL      sub_203D4A4
ROM:0203D5A8                 CMP     R0, #1
ROM:0203D5AC                 BNE     loc_203D5C8
ROM:0203D5B0                 LDRB    R1, [R4]
ROM:0203D5B4                 ADR     R0, aInstall_tonerD ; "\r\n INSTALL_TONER [%d] "
ROM:0203D5B8                 BL      sub_1FF2738
ROM:0203D5BC                 MOV     R0, #1
ROM:0203D5C0                 ADD     SP, SP, #0x60
ROM:0203D5C4                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D5C8 ; ---------------------------------------------------------------------------
ROM:0203D5C8
ROM:0203D5C8 loc_203D5C8                             ; CODE XREF: sub_203D548+64j
ROM:0203D5C8                 ADD     R1, SP, #0x50
ROM:0203D5CC                 MOV     R2, #8
ROM:0203D5D0                 MOV     R0, #0x10
ROM:0203D5D4                 BL      sub_1D849EC
ROM:0203D5D8                 LDRB    R0, [SP,#0x56]
ROM:0203D5DC                 CMP     R0, #0x90
ROM:0203D5E0                 LDREQB  R0, [SP,#0x57]
ROM:0203D5E4                 CMPEQ   R0, #0x1B
ROM:0203D5E8                 BEQ     loc_203D5F8
ROM:0203D5EC                 LDRB    R1, [R4]
ROM:0203D5F0                 ADR     R0, aSchipv1_0__inv ; "\r\n sCHIPv1.0..Invalid [%d] "
ROM:0203D5F4                 BL      sub_1FF2738
ROM:0203D5F8
ROM:0203D5F8 loc_203D5F8                             ; CODE XREF: sub_203D548+A0j
ROM:0203D5F8                 ADD     R0, SP, #0x58
ROM:0203D5FC                 ADR     R1, aSecprt     
ROM:0203D600                 MOV     R2, #6
ROM:0203D604                 BL      memcpy          
ROM:0203D608                 MOV     R0, #0
ROM:0203D60C
ROM:0203D60C loc_203D60C                             ; CODE XREF: sub_203D548+F8j
ROM:0203D60C                 ADD     R1, SP, #0x50
ROM:0203D610                 LDRB    R1, [R1,R0]
ROM:0203D614                 LDRB    R2, [SP,#0x5E]
ROM:0203D618                 EOR     R1, R2, R1
ROM:0203D61C                 STRB    R1, [SP,#0x5E]
ROM:0203D620                 ADD     R1, SP, #0x50
ROM:0203D624                 LDRB    R1, [R1,R0,LSL#1]
ROM:0203D628                 LDRB    R2, [SP,#0x5F]
ROM:0203D62C                 ADD     R0, R0, #1
ROM:0203D630                 AND     R0, R0, #0xFF
ROM:0203D634                 EOR     R1, R2, R1
ROM:0203D638                 STRB    R1, [SP,#0x5F]
ROM:0203D63C                 CMP     R0, #8
ROM:0203D640                 BLT     loc_203D60C     
ROM:0203D644                 ADD     R1, SP, #0x3C   
ROM:0203D648                 ADD     R0, SP, #0x50   
ROM:0203D64C                 MOV     R2, #0x10
ROM:0203D650                 BL      sub_1DBE83C                                   
ROM:0203D654                 ADD     R2, SP, #0x10
ROM:0203D658                 ADD     R0, SP, #0x3C
ROM:0203D65C                 MOV     R1, #0x10
ROM:0203D660                 BL      SHA_1           
ROM:0203D660                                         
ROM:0203D664                 ADD     R1, SP, #0x18
ROM:0203D668                 ADD     R0, SP, #0x24
ROM:0203D66C                 MOV     R2, #8
ROM:0203D670                 BL      memcpy         
ROM:0203D674                 MOV     R1, SP
ROM:0203D678                 ADD     R0, SP, #0x10   
ROM:0203D67C                 MOV     R2, #0x10
ROM:0203D680                 BL      sub_1DBE83C     
ROM:0203D680                                         
ROM:0203D684                 ADD     R1, SP, #8
ROM:0203D688                 ADD     R0, SP, #0x2C
ROM:0203D68C                 MOV     R2, #8
ROM:0203D690                 BL      memcpy
ROM:0203D694                 ADD     R1, SP, #0x2C
ROM:0203D698                 LDMIA   R1, {R2,R3,R12,LR}
ROM:0203D69C                 ADD     R0, SP, #0x3C
ROM:0203D6A0                 STMIA   R0, {R2,R3,R12,LR}
ROM:0203D6A4                 MOV     R3, #1
ROM:0203D6A8                 MOV     R2, R5
ROM:0203D6AC                 MOV     R0, #1
ROM:0203D6B0                 ADD     R1, SP, #0x3C
ROM:0203D6B4                 BL      sub_203D360
ROM:0203D6B8                 MOV     R5, #2
ROM:0203D6BC                 CMP     R0, #0
ROM:0203D6C0                 BEQ     loc_203D6E4
ROM:0203D6C4                 ADR     R0, aCrumCoreFileFa ; "\r\n[Crum Core file] Fail cm_ActiveSecuri"...
ROM:0203D6C8                 BL      sub_1FF2738
ROM:0203D6CC                 LDRB    R1, [R4]
ROM:0203D6D0                 ADR     R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "
ROM:0203D6D4                 BL      sub_1FF2738
ROM:0203D6D8                 MOV     R0, R5
ROM:0203D6DC                 ADD     SP, SP, #0x60
ROM:0203D6E0                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D6E4 ; ---------------------------------------------------------------------------
ROM:0203D6E4
ROM:0203D6E4 loc_203D6E4                             ; CODE XREF: sub_203D548+178j
ROM:0203D6E4                 ADD     R0, SP, #0x6C+var_48
ROM:0203D6E8                 MOV     R2, #0
ROM:0203D6EC                 MOV     R1, #1
ROM:0203D6F0                 BL      sub_203D148
ROM:0203D6F4                 CMP     R0, #0
ROM:0203D6F8                 BEQ     loc_203D71C
ROM:0203D6FC                 ADR     R0, aCrumCoreFile_0 ; "\r\n[Crum Core file] Fail cm_VerifyPasswo"...
ROM:0203D700                 BL      sub_1FF2738
ROM:0203D704                 LDRB    R1, [R4]
ROM:0203D708                 ADR     R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "
ROM:0203D70C                 BL      sub_1FF2738
ROM:0203D710                 MOV     R0, R5
ROM:0203D714                 ADD     SP, SP, #0x60
ROM:0203D718                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D71C ; ---------------------------------------------------------------------------
ROM:0203D71C
ROM:0203D71C loc_203D71C                             ; CODE XREF: sub_203D548+1B0j
ROM:0203D71C                 MOV     R1, #1
ROM:0203D720                 BL      nullsub_154
ROM:0203D724                 MOV     R0, #0
ROM:0203D728                 ADD     SP, SP, #0x60
ROM:0203D72C                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D72C ; End of function sub_203D548
ROM:0203D72C
ROM:0203D72C ; ---------------------------------------------------------------------------
ROM:0203D730 off_203D730     DCD dword_224A6B0       ; DATA XREF: sub_203D548+54r
ROM:0203D730                                         ; sub_203D7E0+9Cr ...
ROM:0203D734 aInstall_tonerD DCB 0xD,0xA             ; DATA XREF: sub_203D548+6Co
ROM:0203D734                 DCB " INSTALL_TONER [%d] ",0
ROM:0203D74B                 DCB 0
ROM:0203D74C aSchipv1_0__inv DCB 0xD,0xA             ; DATA XREF: sub_203D548+A8o
ROM:0203D74C                                         ; ROM:0203D8BCo ...
ROM:0203D74C                 DCB " sCHIPv1.0..Invalid [%d] ",0
ROM:0203D768 aSecprt         DCB "SECPRT",0          ; DATA XREF: sub_203D548+B4o
ROM:0203D768                                         ; ROM:0203D8C8o
ROM:0203D76F                 DCB 0
ROM:0203D770 aCrumCoreFileFa DCB 0xD,0xA             ; DATA XREF: sub_203D548+17Co
ROM:0203D770                 DCB "[Crum Core file] Fail cm_ActiveSecurity",0
ROM:0203D79A                 DCW 0
ROM:0203D79C aInvalid_tonerD DCB 0xD,0xA             ; DATA XREF: sub_203D548+188o
ROM:0203D79C                                         ; sub_203D548+1C0o
ROM:0203D79C                 DCB " INVALID_TONER [%d] ",0
ROM:0203D7B3                 DCB 0
ROM:0203D7B4 aCrumCoreFile_0 DCB 0xD,0xA             ; DATA XREF: sub_203D548+1B4o
ROM:0203D7B4                 DCB "[Crum Core file] Fail cm_VerifyPassword",0
ROM:0203D7DE                 DCW 0
ROM:0203D7E0

Краткий алгоритм работы такой:

  • Выделяем место в стеке, чистим.

  • Читаем серийный номер, кладем по адресу 0x50

  • Кладем по адресу 0x50 строку “SECPRT”

  • 0203D60C – 0203D640 что то считается из sn и кладется в 5e-5f

  • sub_1DBE83C ; Что-то считает (куда=3c, откуда=50, всего = x0x10)

  • sub_1BA543C ; Что-то считает (куда=10, откуда=3c, всего = x0x10)

  • sub_1DBE83C ; Что-то считает (куда=0x0, откуда=0x10, всего = x0x10)

Под спойлером прокомментировал листинг как я это понимаю.

Листинг функции sub_203D548 с разбором
ROM:0203D548 ; =============== S U B R O U T I N E =======================================
ROM:0203D548
ROM:0203D548
ROM:0203D548 sub_203D548                             ; CODE XREF: sub_1D848C4+34p
ROM:0203D548                                         ; sub_1D84CA8+4p
ROM:0203D548
ROM:0203D548 var_64          = -0x64
ROM:0203D548 var_5C          = -0x5C
ROM:0203D548 var_54          = -0x54
ROM:0203D548 var_48          = -0x48
ROM:0203D548 var_40          = -0x40
ROM:0203D548 var_30          = -0x30
ROM:0203D548 var_1C          = -0x1C
ROM:0203D548 var_16          = -0x16
ROM:0203D548 var_15          = -0x15
ROM:0203D548 var_14          = -0x14
ROM:0203D548 var_E           = -0xE
ROM:0203D548 var_D           = -0xD
ROM:0203D548
ROM:0203D548                 STMFD   SP!, {R4,R5,LR}
ROM:0203D54C                 SUB     SP, SP, #0x60   ; Выделяем блок размером 0x60
ROM:0203D550                 ADD     R0, SP, #0x50
ROM:0203D554                 MOV     R1, #0
ROM:0203D558                 MOV     R2, #0
ROM:0203D55C                 MOV     R3, #0
ROM:0203D560                 MOV     R4, #0
ROM:0203D564                 STMIA   R0, {R1-R4}     ; обнуляем область [0x50-0x60]
ROM:0203D564                                         ;
ROM:0203D568                 ADD     R0, SP, #0x2C
ROM:0203D56C                 MOV     R1, #0
ROM:0203D570                 MOV     R2, #0
ROM:0203D574                 MOV     R4, #0
ROM:0203D578                 MOV     R3, #0
ROM:0203D57C                 STMIA   R0, {R1-R4}     ; обнуляем область [0x2с-0x3с]
ROM:0203D57C                                         ;
ROM:0203D580                 ADD     R0, SP, #0x24
ROM:0203D584                 MOV     R1, #0
ROM:0203D588                 MOV     R2, #0
ROM:0203D58C                 STMIA   R0, {R1,R2}     ; обнуляем область [0x24-(0x24+8)]
ROM:0203D58C                                         ;
ROM:0203D590                 LDR     R4, =0x28A7708
ROM:0203D594                 LDRB    R0, [R4]
ROM:0203D598                 MOV     R1, R0,LSL#4
ROM:0203D59C                 LDR     R0, =dword_224A6B0
ROM:0203D5A0                 STRB    R1, [R0]
ROM:0203D5A4                 BL      sub_203D4A4     ; Кажется проверяет наличие чипа в принципе
ROM:0203D5A8                 CMP     R0, #1
ROM:0203D5AC                 BNE     loc_203D5C8
ROM:0203D5B0                 LDRB    R1, [R4]
ROM:0203D5B4                 ADR     R0, aInstall_tonerD ; "\r\n INSTALL_TONER [%d] "
ROM:0203D5B8                 BL      print
ROM:0203D5BC                 MOV     R0, #1
ROM:0203D5C0                 ADD     SP, SP, #0x60
ROM:0203D5C4                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D5C8 ; ---------------------------------------------------------------------------
ROM:0203D5C8
ROM:0203D5C8 loc_203D5C8                             ; CODE XREF: sub_203D548+64j
ROM:0203D5C8                 ADD     R1, SP, #0x50   ; Мы тут если все хорошо
ROM:0203D5CC                 MOV     R2, #8
ROM:0203D5D0                 MOV     R0, #0x10
ROM:0203D5D4                 BL      sub_1D849EC     ; Думаю тут чтение серийного номера, кладется по адресу 0x50
ROM:0203D5D4                                         ; т.к. далее проверяется его хвост
ROM:0203D5D4                                         ;
ROM:0203D5D8                 LDRB    R0, [SP,#0x56]
ROM:0203D5DC                 CMP     R0, #0x90
ROM:0203D5E0                 LDREQB  R0, [SP,#0x57]
ROM:0203D5E4                 CMPEQ   R0, #0x1B
ROM:0203D5E8                 BEQ     loc_203D5F8     ; если 2 последних символа 90 1B  - чип нормальный
ROM:0203D5EC                 LDRB    R1, [R4]
ROM:0203D5F0                 ADR     R0, aSchipv1_0__inv ; "\r\n sCHIPv1.0..Invalid [%d] "
ROM:0203D5F4                 BL      print
ROM:0203D5F8
ROM:0203D5F8 loc_203D5F8                             ; CODE XREF: sub_203D548+A0j
ROM:0203D5F8                 ADD     R0, SP, #0x58   ; ! Отсюда начинаются манипуляции с серийным номером
ROM:0203D5FC                 ADR     R1, aSecprt     ; "SECPRT"
ROM:0203D600                 MOV     R2, #6
ROM:0203D604                 BL      memcpy          ; копируем SECPRT по адресу 0x58
ROM:0203D608                 MOV     R0, #0
ROM:0203D60C
ROM:0203D60C loc_203D60C                             ; CODE XREF: sub_203D548+F8j
ROM:0203D60C                 ADD     R1, SP, #0x50
ROM:0203D610                 LDRB    R1, [R1,R0]
ROM:0203D614                 LDRB    R2, [SP,#0x5E]
ROM:0203D618                 EOR     R1, R2, R1
ROM:0203D61C                 STRB    R1, [SP,#0x5E]
ROM:0203D620                 ADD     R1, SP, #0x50
ROM:0203D624                 LDRB    R1, [R1,R0,LSL#1]
ROM:0203D628                 LDRB    R2, [SP,#0x5F]
ROM:0203D62C                 ADD     R0, R0, #1
ROM:0203D630                 AND     R0, R0, #0xFF
ROM:0203D634                 EOR     R1, R2, R1
ROM:0203D638                 STRB    R1, [SP,#0x5F]
ROM:0203D63C                 CMP     R0, #8
ROM:0203D640                 BLT     loc_203D60C     ; hash SN по адресу 0x5e - 0x5f
ROM:0203D644                 ADD     R1, SP, #0x3C   ; r1 = 3c
ROM:0203D648                 ADD     R0, SP, #0x50   ; r0 = 50
ROM:0203D64C                 MOV     R2, #0x10
ROM:0203D650                 BL      sub_1DBE83C     ; Что-то считает (куда=3c, откуда=50, всего = x0x10)
ROM:0203D650                                         ;
ROM:0203D654                 ADD     R2, SP, #0x10
ROM:0203D658                 ADD     R0, SP, #0x3C
ROM:0203D65C                 MOV     R1, #0x10
ROM:0203D660                 BL      sub_1BA543C     ; Что-то считает (куда=10, откуда=3c, всего = x0x10)
ROM:0203D664                 ADD     R1, SP, #0x18
ROM:0203D668                 ADD     R0, SP, #0x24
ROM:0203D66C                 MOV     R2, #8
ROM:0203D670                 BL      memcpy
ROM:0203D674                 MOV     R1, SP
ROM:0203D678                 ADD     R0, SP, #0x10
ROM:0203D67C                 MOV     R2, #0x10
ROM:0203D680                 BL      sub_1DBE83C     ; опять что-то считает (куда=0x0, откуда=0x10, всего = x0x10)
ROM:0203D684                 ADD     R1, SP, #8
ROM:0203D688                 ADD     R0, SP, #0x2C
ROM:0203D68C                 MOV     R2, #8
ROM:0203D690                 BL      memcpy
ROM:0203D694                 ADD     R1, SP, #0x2C
ROM:0203D698                 LDMIA   R1, {R2,R3,R12,LR}
ROM:0203D69C                 ADD     R0, SP, #0x3C
ROM:0203D6A0                 STMIA   R0, {R2,R3,R12,LR}
ROM:0203D6A4                 MOV     R3, #1
ROM:0203D6A8                 MOV     R2, R5
ROM:0203D6AC                 MOV     R0, #1
ROM:0203D6B0                 ADD     R1, SP, #0x3C   ; значит в 3c auth-pass
ROM:0203D6B0                                         ; до этого копировали c 0x8 в 0x2с, c 0x2c в 0x3c
ROM:0203D6B4                 BL      sub_203D360     ; Вероятно авторизация
ROM:0203D6B8                 MOV     R5, #2
ROM:0203D6BC                 CMP     R0, #0
ROM:0203D6C0                 BEQ     loc_203D6E4
ROM:0203D6C4                 ADR     R0, aCrumCoreFileFa ; "\r\n[Crum Core file] Fail cm_ActiveSecuri"...
ROM:0203D6C8                 BL      print
ROM:0203D6CC                 LDRB    R1, [R4]
ROM:0203D6D0                 ADR     R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "
ROM:0203D6D4                 BL      print
ROM:0203D6D8                 MOV     R0, R5
ROM:0203D6DC                 ADD     SP, SP, #0x60
ROM:0203D6E0                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D6E4 ; ---------------------------------------------------------------------------
ROM:0203D6E4
ROM:0203D6E4 loc_203D6E4                             ; CODE XREF: sub_203D548+178j
ROM:0203D6E4                 ADD     R0, SP, #0x24   ; значит в 0x24 write-pass
ROM:0203D6E8                 MOV     R2, #0
ROM:0203D6EC                 MOV     R1, #1
ROM:0203D6F0                 BL      sub_203D148     ; Вероятно запись после успешной авторизации
ROM:0203D6F0                                         ;
ROM:0203D6F4                 CMP     R0, #0
ROM:0203D6F8                 BEQ     loc_203D71C
ROM:0203D6FC                 ADR     R0, aCrumCoreFile_0 ; "\r\n[Crum Core file] Fail cm_VerifyPasswo"...
ROM:0203D700                 BL      print
ROM:0203D704                 LDRB    R1, [R4]
ROM:0203D708                 ADR     R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "
ROM:0203D70C                 BL      print
ROM:0203D710                 MOV     R0, R5
ROM:0203D714                 ADD     SP, SP, #0x60
ROM:0203D718                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D71C ; ---------------------------------------------------------------------------
ROM:0203D71C
ROM:0203D71C loc_203D71C                             ; CODE XREF: sub_203D548+1B0j
ROM:0203D71C                 MOV     R1, #1
ROM:0203D720                 BL      nullsub_154
ROM:0203D724                 MOV     R0, #0
ROM:0203D728                 ADD     SP, SP, #0x60
ROM:0203D72C                 LDMFD   SP!, {R4,R5,PC}
ROM:0203D72C ; End of function sub_203D548

Выходит, что по сути нужны 2 функции 1DBE83C и 1BA543C. Посмотрим в эмуляторе какой результат они возвращают, если повезет - попробуем подобрать что-то стандартное, если нет - будем их разбирать.

Пишем первую версию:

mem = bytearray(0x60)

#serial = input("SN:")
serial = "112233445566901B"
auth, write = generate_passwords(serial)

dump(mem, 0, 0x60)


def dump(tab,start, ln):
    for offset in range(start, start + ln, 16):
        chunk = tab[offset:offset + 16]
        print(f"{hex(offset)}: {' '.join(f'{b:02X}' for b in chunk)}" )

def generate_passwords(serial_hex):
    global mem
    sn_bytes = bytes.fromhex(serial_hex)
    if not((sn_bytes[6]==0x90) & (sn_bytes[7]==0x1B)):
        print ("not ss02-1 crum")
        return bytes.fromhex("00"), bytes.fromhex("00")

    mem[0x50:0x58] = sn_bytes
    mem[0x58:0x5E] = b"SECPRT"

    mem[0x5E] = 0
    mem[0x5F] = 0
    for r0 in range(8):
        mem[0x5E] = mem[0x5E] ^ mem[0x50 + r0]
        mem[0x5F] = mem[0x5F] ^ mem[0x50 + (r0 << 1)]

    sub_1DBE83C (r0 = 0x50, r1 = 0x3c, r2 = 0x10)

    sub_1BA543C (r0 = 0x3c, r1, 0x10, r2 = 0x10)

    mem [0x24:0x2c] = mem[0x18:0x20]

    sub_1DBE83C (r0 = 0x10, r1 = 0x0, r2 = 0x10)

    mem[0x2c:0x2c+8] = mem[0x8:0x10]
    auth_pass = mem[0x2c:0x2C+8]
    write_pass = mem[0x24:0x27]
    return auth_pass, write_pass

def sub_1DBE83C (r0, r1, r2):
    return

def sub_1BA543C (r0, r1, r2)
    return

Результат:

0x0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x50: 11 22 33 44 55 66 90 1B 53 45 43 50 52 54 FC 59

Эмуляция, получение результата

Запускаем эмулятор. Первым делом надо выбрать тип процессора, установить режим bigendian, включить. CPU \ System Settings…

Настраиваем окошки: листинг (View / List Source), регистры (View / Registers), дамп по адресу 0x0 (View / Dump…)- там будем собирать результат. Кликая в дампе по адресам 0x50 – 0x58 вводим свой серийник.

Все команды по сути выполняются в командной строке внизу окна. Если мы кликаем на адрес памяти для модификации система автоматически пишет команду для изменения значения по этому адресу, нам остается толко ввести значение. Например при заполнении серийника создалась команда "SD:0x50 %LE ". При модификации регистра PC - "R.S PC ", сокращенно от "REGISTER.SET PC ", такая команда тоже работает. Под командной строкой есть кнопки, отображающие какие команды доступны на текущем этапе. Можно натыкивать команды кнопками, пока не запомнте те что нужны. Дальше нужно загрузить прошивку, установить значения регистров. Для загрузки дампа натыкиваем кнопками:

DATA.LOAD.BINARY "kernel.bin" 0x1B60000
R.S PC 0x203D5D8

Мы в начале пути, 0x203D5D8 выбран потому что это начало проверки хвоста серийника. F2 - пошаговое выполнение команды, F3 - не заходя в процедуры. Прошагиваем весь код по F3 до 0203D644, перед началом вызова функций.

Результат:

Смотрим хвост, FC 59, сошлось, ура ! ) Можно прошагать до конца, посмотреть как заполняется область памяти. На этом этапе я бы хотел сделать небольшое отступление. В процессе отладки придется не раз начинать с начала, каждый раз всё настраивать, дошагивать до нужной точки нереально. В эмуляторе есть инструмент для облегчения задачи - batchfile - командный файл, где мы пишем все команды загрузки, инициализации. Запуск через File / Run batchfile… Доступны все команды, даже отладка, т.е. можно сделать шаги по f2 (команда STEP), запустить на выполнение (GO) установить break - (BREAK.SET). Напишем такой файл:

b::
reset
system.option.bigendian on
system.up
data.load.binary "kernel.bin" 0x1B60000

data.set 0x50 %BYTE 0x11
data.set 0x51 %BYTE 0x22
data.set 0x52 %BYTE 0x33
data.set 0x53 %BYTE 0x44
data.set 0x54 %BYTE 0x55
data.set 0x55 %BYTE 0x66
data.set 0x56 %BYTE 0x90
data.set 0x57 %BYTE 0x1B

register.set.pc 0x203D5D8

b.s 0x0203D644
go

Всё, теперь мы опять в той же точке без настроек. Еще дополнение: система не ждет прохождение до точки останова. Если сразу после go сохранить результат, то он может оказаться не готов. Если задача остановиться после вызова процедуры и сохранить результат, нужно дать время на выполнение этой функции. В интерактивном режиме мы видим когда процессор занят, в batch файле нет, команды начнут выполняться дальше не дожидаясь. Чтобы решить это нужно вставить паузу, команда WAIT, например “wait 200.ms”. Какую паузу ставить решаете сами, предварительно оценив время выполнения функции руками.

Пробежимся по функциям, выпишем результат после каждой:

sub_1DBE83C(11 22 33 44 55 66 90 1B 53 45 43 50 52 54 FC 59) = 78 07 FE 92 F2 4F 15 61 D6 A7 9A CE 85 07 82 65

sub_1BA543C(78 07 FE 92 F2 4F 15 61 D6 A7 9A CE 85 07 82 65) = E7 16 A6 FE 0E 4D 16 FC 26 85 1F 08 FD 9C FC 30 2E 2A 66 2F

sub_1DBE83C(E7 16 A6 FE 0E 4D 16 FC 26 85 1F 08 FD 9C FC 30) = 3F AC 9A 28 5C 8E 1D 2D 39 1B 22 CD 6D D7 B5 C4

Самым логичным ходом будет попробовать подобрать готовые алгоритмы, вдруг повезет. Пишем тест:

import hashlib

def test_alg(source, res_ok):
    alg = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
           'blake2b', 'blake2s',
           'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512')
    for name in alg:
        if hashlib.new(name, source).hexdigest() == res_ok.hex():
            return name
    return False

tests =(
(bytes.fromhex("11 22 33 44 55 66 90 1B 53 45 43 50 52 54 FC 59"), bytes.fromhex("78 07 FE 92 F2 4F 15 61 D6 A7 9A CE 85 07 82 65")),
(bytes.fromhex("78 07 FE 92 F2 4F 15 61 D6 A7 9A CE 85 07 82 65"), bytes.fromhex("E7 16 A6 FE 0E 4D 16 FC 26 85 1F 08 FD 9C FC 30 2E 2A 66 2F")),
(bytes.fromhex("E7 16 A6 FE 0E 4D 16 FC 26 85 1F 08 FD 9C FC 30"), bytes.fromhex("3F AC 9A 28 5C 8E 1D 2D 39 1B 22 CD 6D D7 B5 C4"))
)

for i, tst in enumerate(tests):
    print (i,  test_alg (tst[0], tst[1]))

Результат:

0 False
1 sha1
2 False

Бинго! sub_1BA543C - это SHA-1, можно использовать библиотечную функцию, откровенно говоря - повезло ) Едем дальше, открываем sub_1DBE83C. Выглядит не страшно, всего 2 вызова:

ROM:01DBE83C sub_1DBE83C                                                                   
ROM:01DBE83C                 STMFD   SP!, {R4,R5,LR}
ROM:01DBE840                 SUB     SP, SP, #0xA0	; свой блок данных размером 0xA0
ROM:01DBE844                 MOV     R4, R1
ROM:01DBE848                 LDR     R1, =0x2105B04	; тут лежат константы
ROM:01DBE84C                 MOV     R5, R0
ROM:01DBE850                 LDMIA   R1, {R1,R3,R12,LR}
ROM:01DBE854                 ADD     R0, SP, #0x10
ROM:01DBE858                 STMIA   R0, {R1,R3,R12,LR}	; запишем себе
ROM:01DBE85C                 LDR     R1, =0x2105B14	; и тут константы
ROM:01DBE860                 MOV     R0, SP
ROM:01DBE864                 LDMIA   R1, {R1,R3,R12,LR}
ROM:01DBE868                 STMIA   R0, {R1,R3,R12,LR}
ROM:01DBE86C                 ADD     R1, SP, #0x20
ROM:01DBE870                 ADD     R0, SP, #0x10
ROM:01DBE874                 BL      sub_1DBC554
ROM:01DBE878                 ADD     R2, SP, #0x20   
ROM:01DBE87C                 MOV     R1, R4          
ROM:01DBE880                 MOV     R0, R5          
ROM:01DBE884                 BL      sub_1DBCEF0
ROM:01DBE888                 ADD     SP, SP, #0xA0
ROM:01DBE88C                 LDMFD   SP!, {R4,R5,PC}
ROM:01DBE88C ; End of function sub_1DBE83C

Посмотрим что в параметрах у sub_1DBC554, что будет после:

Осталось разобрать sub_1DBC554 и sub_1DBCEF0 и дело сделано.

Пожалуй прервусь на этом этапе, функции достаточно объемные, если будет интерес то напишу 2ю часть )

p.s. Посмотрел на сайте http_s://www.support.xerox.com/en-us/content/121246, есть версия новее - 15.007.01.000, но переделывать всё не хочется, т.к. изменились адреса загрузки ядра, соответственно и все процедуры сдвинулись… Если есть желание можете пройти этот путь с новой прошивкой, думаю результат будет тот же.

Комментарии (3)


  1. hddscan
    30.07.2026 14:37

    У IDA есть декомпилятор для АРМ-а, сильно упрощает понимание кода.


    1. Koluchy
      30.07.2026 14:37

      А findcrypt и ему подобные плагины отлично помогают в идентификации криптоалгоритмов...


    1. pMalice Автор
      30.07.2026 14:37

      Соглашусь. Но эмуляция позволяет получить результат функции до анализа алгоритма, дает понимание конечного результата. Очень полезный инструмент.