Постановка задачи
Есть устройство, работает с чипами ss02-1, умеет в них писать и читать. Для этого в себе содержит алгоритмы генерации паролей на авторизацию и запись, мы хотим разобрать алгоритм и написать код, который будет выдавать тот же результат.
Что имеем — прошивку устройства, серийный номер чипа, на основание которого генерируются пароли. Устройство xerox wc 4250, прошивка у меня в наличии версии 15.003.70.000.
Выбор инструментов
-
На первом месте Ida. Интерактивный дизассемблер, инструмент для анализа кода, загрузим прошивку, восстановим порядок генерации, определим какие функции что делают, построим первоначальный каркас будущей программы.
-
TRACE32 Arm Debugger от lauterbach. Откровенно говоря, у меня старая версия, в about написано Release Jun 2011. Возможно сейчас есть и другие инструменты, но и этот отлично справляется с задачей. В нем можно создать виртуальную среду, выбрать тип эмулируемого процессора, загрузить прошивку, запустить на выполнение и получить результат. Можно выполнять пошагово сверяясь со своим кодом, искать ошибки.
-
Python — тут пишем код.
Первый взгляд
Для начала нужно достать из прошивки ядро, оно после сигнатуры “$ZIP”, начиная с 0x78 0x9C — zip архив. Пишем код:
import zlibdef 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 reswith open("WC4250_15.003.70.000.hd", 'rb') as f: data = f.read()pos = 0while 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+34pROM:0203D548 ; sub_1D84CA8+4pROM:0203D548ROM:0203D548 var_64 = -0x64ROM:0203D548 var_5C = -0x5CROM:0203D548 var_54 = -0x54ROM:0203D548 var_48 = -0x48ROM:0203D548 var_40 = -0x40ROM:0203D548 var_30 = -0x30ROM:0203D548 var_1C = -0x1CROM:0203D548 var_16 = -0x16ROM:0203D548 var_15 = -0x15ROM:0203D548 var_14 = -0x14ROM:0203D548 var_E = -0xEROM:0203D548 var_D = -0xDROM:0203D548ROM:0203D548 STMFD SP!, {R4,R5,LR}ROM:0203D54C SUB SP, SP, #0x60ROM:0203D550 ADD R0, SP, #0x50ROM:0203D554 MOV R1, #0ROM:0203D558 MOV R2, #0ROM:0203D55C MOV R3, #0ROM:0203D560 MOV R4, #0ROM:0203D564 STMIA R0, {R1-R4} ROM:0203D568 ADD R0, SP, #0x2CROM:0203D56C MOV R1, #0ROM:0203D570 MOV R2, #0ROM:0203D574 MOV R4, #0ROM:0203D578 MOV R3, #0ROM:0203D57C STMIA R0, {R1-R4}ROM:0203D580 ADD R0, SP, #0x24ROM:0203D584 MOV R1, #0ROM:0203D588 MOV R2, #0ROM:0203D58C STMIA R0, {R1,R2}ROM:0203D590 LDR R4, =0x28A7708ROM:0203D594 LDRB R0, [R4]ROM:0203D598 MOV R1, R0,LSL#4ROM:0203D59C LDR R0, =dword_224A6B0ROM:0203D5A0 STRB R1, [R0]ROM:0203D5A4 BL sub_203D4A4ROM:0203D5A8 CMP R0, #1ROM:0203D5AC BNE loc_203D5C8ROM:0203D5B0 LDRB R1, [R4]ROM:0203D5B4 ADR R0, aInstall_tonerD ; "\r\n INSTALL_TONER [%d] "ROM:0203D5B8 BL sub_1FF2738ROM:0203D5BC MOV R0, #1ROM:0203D5C0 ADD SP, SP, #0x60ROM:0203D5C4 LDMFD SP!, {R4,R5,PC}ROM:0203D5C8 ; ---------------------------------------------------------------------------ROM:0203D5C8ROM:0203D5C8 loc_203D5C8 ; CODE XREF: sub_203D548+64jROM:0203D5C8 ADD R1, SP, #0x50ROM:0203D5CC MOV R2, #8ROM:0203D5D0 MOV R0, #0x10ROM:0203D5D4 BL sub_1D849ECROM:0203D5D8 LDRB R0, [SP,#0x56]ROM:0203D5DC CMP R0, #0x90ROM:0203D5E0 LDREQB R0, [SP,#0x57]ROM:0203D5E4 CMPEQ R0, #0x1BROM:0203D5E8 BEQ loc_203D5F8ROM:0203D5EC LDRB R1, [R4]ROM:0203D5F0 ADR R0, aSchipv1_0__inv ; "\r\n sCHIPv1.0..Invalid [%d] "ROM:0203D5F4 BL sub_1FF2738ROM:0203D5F8ROM:0203D5F8 loc_203D5F8 ; CODE XREF: sub_203D548+A0jROM:0203D5F8 ADD R0, SP, #0x58ROM:0203D5FC ADR R1, aSecprt ROM:0203D600 MOV R2, #6ROM:0203D604 BL memcpy ROM:0203D608 MOV R0, #0ROM:0203D60CROM:0203D60C loc_203D60C ; CODE XREF: sub_203D548+F8jROM:0203D60C ADD R1, SP, #0x50ROM:0203D610 LDRB R1, [R1,R0]ROM:0203D614 LDRB R2, [SP,#0x5E]ROM:0203D618 EOR R1, R2, R1ROM:0203D61C STRB R1, [SP,#0x5E]ROM:0203D620 ADD R1, SP, #0x50ROM:0203D624 LDRB R1, [R1,R0,LSL#1]ROM:0203D628 LDRB R2, [SP,#0x5F]ROM:0203D62C ADD R0, R0, #1ROM:0203D630 AND R0, R0, #0xFFROM:0203D634 EOR R1, R2, R1ROM:0203D638 STRB R1, [SP,#0x5F]ROM:0203D63C CMP R0, #8ROM:0203D640 BLT loc_203D60C ROM:0203D644 ADD R1, SP, #0x3C ROM:0203D648 ADD R0, SP, #0x50 ROM:0203D64C MOV R2, #0x10ROM:0203D650 BL sub_1DBE83C ROM:0203D654 ADD R2, SP, #0x10ROM:0203D658 ADD R0, SP, #0x3CROM:0203D65C MOV R1, #0x10ROM:0203D660 BL SHA_1 ROM:0203D660 ROM:0203D664 ADD R1, SP, #0x18ROM:0203D668 ADD R0, SP, #0x24ROM:0203D66C MOV R2, #8ROM:0203D670 BL memcpy ROM:0203D674 MOV R1, SPROM:0203D678 ADD R0, SP, #0x10 ROM:0203D67C MOV R2, #0x10ROM:0203D680 BL sub_1DBE83C ROM:0203D680 ROM:0203D684 ADD R1, SP, #8ROM:0203D688 ADD R0, SP, #0x2CROM:0203D68C MOV R2, #8ROM:0203D690 BL memcpyROM:0203D694 ADD R1, SP, #0x2CROM:0203D698 LDMIA R1, {R2,R3,R12,LR}ROM:0203D69C ADD R0, SP, #0x3CROM:0203D6A0 STMIA R0, {R2,R3,R12,LR}ROM:0203D6A4 MOV R3, #1ROM:0203D6A8 MOV R2, R5ROM:0203D6AC MOV R0, #1ROM:0203D6B0 ADD R1, SP, #0x3CROM:0203D6B4 BL sub_203D360ROM:0203D6B8 MOV R5, #2ROM:0203D6BC CMP R0, #0ROM:0203D6C0 BEQ loc_203D6E4ROM:0203D6C4 ADR R0, aCrumCoreFileFa ; "\r\n[Crum Core file] Fail cm_ActiveSecuri"...ROM:0203D6C8 BL sub_1FF2738ROM:0203D6CC LDRB R1, [R4]ROM:0203D6D0 ADR R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "ROM:0203D6D4 BL sub_1FF2738ROM:0203D6D8 MOV R0, R5ROM:0203D6DC ADD SP, SP, #0x60ROM:0203D6E0 LDMFD SP!, {R4,R5,PC}ROM:0203D6E4 ; ---------------------------------------------------------------------------ROM:0203D6E4ROM:0203D6E4 loc_203D6E4 ; CODE XREF: sub_203D548+178jROM:0203D6E4 ADD R0, SP, #0x6C+var_48ROM:0203D6E8 MOV R2, #0ROM:0203D6EC MOV R1, #1ROM:0203D6F0 BL sub_203D148ROM:0203D6F4 CMP R0, #0ROM:0203D6F8 BEQ loc_203D71CROM:0203D6FC ADR R0, aCrumCoreFile_0 ; "\r\n[Crum Core file] Fail cm_VerifyPasswo"...ROM:0203D700 BL sub_1FF2738ROM:0203D704 LDRB R1, [R4]ROM:0203D708 ADR R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "ROM:0203D70C BL sub_1FF2738ROM:0203D710 MOV R0, R5ROM:0203D714 ADD SP, SP, #0x60ROM:0203D718 LDMFD SP!, {R4,R5,PC}ROM:0203D71C ; ---------------------------------------------------------------------------ROM:0203D71CROM:0203D71C loc_203D71C ; CODE XREF: sub_203D548+1B0jROM:0203D71C MOV R1, #1ROM:0203D720 BL nullsub_154ROM:0203D724 MOV R0, #0ROM:0203D728 ADD SP, SP, #0x60ROM:0203D72C LDMFD SP!, {R4,R5,PC}ROM:0203D72C ; End of function sub_203D548ROM:0203D72CROM:0203D72C ; ---------------------------------------------------------------------------ROM:0203D730 off_203D730 DCD dword_224A6B0 ; DATA XREF: sub_203D548+54rROM:0203D730 ; sub_203D7E0+9Cr ...ROM:0203D734 aInstall_tonerD DCB 0xD,0xA ; DATA XREF: sub_203D548+6CoROM:0203D734 DCB " INSTALL_TONER [%d] ",0ROM:0203D74B DCB 0ROM:0203D74C aSchipv1_0__inv DCB 0xD,0xA ; DATA XREF: sub_203D548+A8oROM:0203D74C ; ROM:0203D8BCo ...ROM:0203D74C DCB " sCHIPv1.0..Invalid [%d] ",0ROM:0203D768 aSecprt DCB "SECPRT",0 ; DATA XREF: sub_203D548+B4oROM:0203D768 ; ROM:0203D8C8oROM:0203D76F DCB 0ROM:0203D770 aCrumCoreFileFa DCB 0xD,0xA ; DATA XREF: sub_203D548+17CoROM:0203D770 DCB "[Crum Core file] Fail cm_ActiveSecurity",0ROM:0203D79A DCW 0ROM:0203D79C aInvalid_tonerD DCB 0xD,0xA ; DATA XREF: sub_203D548+188oROM:0203D79C ; sub_203D548+1C0oROM:0203D79C DCB " INVALID_TONER [%d] ",0ROM:0203D7B3 DCB 0ROM:0203D7B4 aCrumCoreFile_0 DCB 0xD,0xA ; DATA XREF: sub_203D548+1B4oROM:0203D7B4 DCB "[Crum Core file] Fail cm_VerifyPassword",0ROM:0203D7DE DCW 0ROM: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:0203D548ROM:0203D548ROM:0203D548 sub_203D548 ; CODE XREF: sub_1D848C4+34pROM:0203D548 ; sub_1D84CA8+4pROM:0203D548ROM:0203D548 var_64 = -0x64ROM:0203D548 var_5C = -0x5CROM:0203D548 var_54 = -0x54ROM:0203D548 var_48 = -0x48ROM:0203D548 var_40 = -0x40ROM:0203D548 var_30 = -0x30ROM:0203D548 var_1C = -0x1CROM:0203D548 var_16 = -0x16ROM:0203D548 var_15 = -0x15ROM:0203D548 var_14 = -0x14ROM:0203D548 var_E = -0xEROM:0203D548 var_D = -0xDROM:0203D548ROM:0203D548 STMFD SP!, {R4,R5,LR}ROM:0203D54C SUB SP, SP, #0x60 ; Выделяем блок размером 0x60ROM:0203D550 ADD R0, SP, #0x50ROM:0203D554 MOV R1, #0ROM:0203D558 MOV R2, #0ROM:0203D55C MOV R3, #0ROM:0203D560 MOV R4, #0ROM:0203D564 STMIA R0, {R1-R4} ; обнуляем область [0x50-0x60]ROM:0203D564 ;ROM:0203D568 ADD R0, SP, #0x2CROM:0203D56C MOV R1, #0ROM:0203D570 MOV R2, #0ROM:0203D574 MOV R4, #0ROM:0203D578 MOV R3, #0ROM:0203D57C STMIA R0, {R1-R4} ; обнуляем область [0x2с-0x3с]ROM:0203D57C ;ROM:0203D580 ADD R0, SP, #0x24ROM:0203D584 MOV R1, #0ROM:0203D588 MOV R2, #0ROM:0203D58C STMIA R0, {R1,R2} ; обнуляем область [0x24-(0x24+8)]ROM:0203D58C ;ROM:0203D590 LDR R4, =0x28A7708ROM:0203D594 LDRB R0, [R4]ROM:0203D598 MOV R1, R0,LSL#4ROM:0203D59C LDR R0, =dword_224A6B0ROM:0203D5A0 STRB R1, [R0]ROM:0203D5A4 BL sub_203D4A4 ; Кажется проверяет наличие чипа в принципеROM:0203D5A8 CMP R0, #1ROM:0203D5AC BNE loc_203D5C8ROM:0203D5B0 LDRB R1, [R4]ROM:0203D5B4 ADR R0, aInstall_tonerD ; "\r\n INSTALL_TONER [%d] "ROM:0203D5B8 BL printROM:0203D5BC MOV R0, #1ROM:0203D5C0 ADD SP, SP, #0x60ROM:0203D5C4 LDMFD SP!, {R4,R5,PC}ROM:0203D5C8 ; ---------------------------------------------------------------------------ROM:0203D5C8ROM:0203D5C8 loc_203D5C8 ; CODE XREF: sub_203D548+64jROM:0203D5C8 ADD R1, SP, #0x50 ; Мы тут если все хорошоROM:0203D5CC MOV R2, #8ROM:0203D5D0 MOV R0, #0x10ROM:0203D5D4 BL sub_1D849EC ; Думаю тут чтение серийного номера, кладется по адресу 0x50ROM:0203D5D4 ; т.к. далее проверяется его хвостROM:0203D5D4 ;ROM:0203D5D8 LDRB R0, [SP,#0x56]ROM:0203D5DC CMP R0, #0x90ROM:0203D5E0 LDREQB R0, [SP,#0x57]ROM:0203D5E4 CMPEQ R0, #0x1BROM: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 printROM:0203D5F8ROM:0203D5F8 loc_203D5F8 ; CODE XREF: sub_203D548+A0jROM:0203D5F8 ADD R0, SP, #0x58 ; ! Отсюда начинаются манипуляции с серийным номеромROM:0203D5FC ADR R1, aSecprt ; "SECPRT"ROM:0203D600 MOV R2, #6ROM:0203D604 BL memcpy ; копируем SECPRT по адресу 0x58ROM:0203D608 MOV R0, #0ROM:0203D60CROM:0203D60C loc_203D60C ; CODE XREF: sub_203D548+F8jROM:0203D60C ADD R1, SP, #0x50ROM:0203D610 LDRB R1, [R1,R0]ROM:0203D614 LDRB R2, [SP,#0x5E]ROM:0203D618 EOR R1, R2, R1ROM:0203D61C STRB R1, [SP,#0x5E]ROM:0203D620 ADD R1, SP, #0x50ROM:0203D624 LDRB R1, [R1,R0,LSL#1]ROM:0203D628 LDRB R2, [SP,#0x5F]ROM:0203D62C ADD R0, R0, #1ROM:0203D630 AND R0, R0, #0xFFROM:0203D634 EOR R1, R2, R1ROM:0203D638 STRB R1, [SP,#0x5F]ROM:0203D63C CMP R0, #8ROM:0203D640 BLT loc_203D60C ; hash SN по адресу 0x5e - 0x5fROM:0203D644 ADD R1, SP, #0x3C ; r1 = 3cROM:0203D648 ADD R0, SP, #0x50 ; r0 = 50ROM:0203D64C MOV R2, #0x10ROM:0203D650 BL sub_1DBE83C ; Что-то считает (куда=3c, откуда=50, всего = x0x10)ROM:0203D650 ;ROM:0203D654 ADD R2, SP, #0x10ROM:0203D658 ADD R0, SP, #0x3CROM:0203D65C MOV R1, #0x10ROM:0203D660 BL sub_1BA543C ; Что-то считает (куда=10, откуда=3c, всего = x0x10)ROM:0203D664 ADD R1, SP, #0x18ROM:0203D668 ADD R0, SP, #0x24ROM:0203D66C MOV R2, #8ROM:0203D670 BL memcpyROM:0203D674 MOV R1, SPROM:0203D678 ADD R0, SP, #0x10ROM:0203D67C MOV R2, #0x10ROM:0203D680 BL sub_1DBE83C ; опять что-то считает (куда=0x0, откуда=0x10, всего = x0x10)ROM:0203D684 ADD R1, SP, #8ROM:0203D688 ADD R0, SP, #0x2CROM:0203D68C MOV R2, #8ROM:0203D690 BL memcpyROM:0203D694 ADD R1, SP, #0x2CROM:0203D698 LDMIA R1, {R2,R3,R12,LR}ROM:0203D69C ADD R0, SP, #0x3CROM:0203D6A0 STMIA R0, {R2,R3,R12,LR}ROM:0203D6A4 MOV R3, #1ROM:0203D6A8 MOV R2, R5ROM:0203D6AC MOV R0, #1ROM:0203D6B0 ADD R1, SP, #0x3C ; значит в 3c auth-passROM:0203D6B0 ; до этого копировали c 0x8 в 0x2с, c 0x2c в 0x3cROM:0203D6B4 BL sub_203D360 ; Вероятно авторизацияROM:0203D6B8 MOV R5, #2ROM:0203D6BC CMP R0, #0ROM:0203D6C0 BEQ loc_203D6E4ROM:0203D6C4 ADR R0, aCrumCoreFileFa ; "\r\n[Crum Core file] Fail cm_ActiveSecuri"...ROM:0203D6C8 BL printROM:0203D6CC LDRB R1, [R4]ROM:0203D6D0 ADR R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "ROM:0203D6D4 BL printROM:0203D6D8 MOV R0, R5ROM:0203D6DC ADD SP, SP, #0x60ROM:0203D6E0 LDMFD SP!, {R4,R5,PC}ROM:0203D6E4 ; ---------------------------------------------------------------------------ROM:0203D6E4ROM:0203D6E4 loc_203D6E4 ; CODE XREF: sub_203D548+178jROM:0203D6E4 ADD R0, SP, #0x24 ; значит в 0x24 write-passROM:0203D6E8 MOV R2, #0ROM:0203D6EC MOV R1, #1ROM:0203D6F0 BL sub_203D148 ; Вероятно запись после успешной авторизацииROM:0203D6F0 ;ROM:0203D6F4 CMP R0, #0ROM:0203D6F8 BEQ loc_203D71CROM:0203D6FC ADR R0, aCrumCoreFile_0 ; "\r\n[Crum Core file] Fail cm_VerifyPasswo"...ROM:0203D700 BL printROM:0203D704 LDRB R1, [R4]ROM:0203D708 ADR R0, aInvalid_tonerD ; "\r\n INVALID_TONER [%d] "ROM:0203D70C BL printROM:0203D710 MOV R0, R5ROM:0203D714 ADD SP, SP, #0x60ROM:0203D718 LDMFD SP!, {R4,R5,PC}ROM:0203D71C ; ---------------------------------------------------------------------------ROM:0203D71CROM:0203D71C loc_203D71C ; CODE XREF: sub_203D548+1B0jROM:0203D71C MOV R1, #1ROM:0203D720 BL nullsub_154ROM:0203D724 MOV R0, #0ROM:0203D728 ADD SP, SP, #0x60ROM: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_passdef sub_1DBE83C (r0, r1, r2): returndef sub_1BA543C (r0, r1, r2) return
Результат:
0x0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 000x50: 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" 0x1B60000R.S PC 0x203D5D8

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

Смотрим хвост, FC 59, сошлось, ура ! ) Можно прошагать до конца, посмотреть как заполняется область памяти. На этом этапе я бы хотел сделать небольшое отступление. В процессе отладки придется не раз начинать с начала, каждый раз всё настраивать, дошагивать до нужной точки нереально. В эмуляторе есть инструмент для облегчения задачи — batchfile — командный файл, где мы пишем все команды загрузки, инициализации. Запуск через File / Run batchfile… Доступны все команды, даже отладка, т.е. можно сделать шаги по f2 (команда STEP), запустить на выполнение (GO) установить break — (BREAK.SET). Напишем такой файл:
b::resetsystem.option.bigendian onsystem.updata.load.binary "kernel.bin" 0x1B60000data.set 0x50 %BYTE 0x11data.set 0x51 %BYTE 0x22data.set 0x52 %BYTE 0x33data.set 0x53 %BYTE 0x44data.set 0x54 %BYTE 0x55data.set 0x55 %BYTE 0x66data.set 0x56 %BYTE 0x90data.set 0x57 %BYTE 0x1Bregister.set.pc 0x203D5D8b.s 0x0203D644go
Всё, теперь мы опять в той же точке без настроек. Еще дополнение: система не ждет прохождение до точки останова. Если сразу после 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 65sub_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 2Fsub_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 hashlibdef 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 Falsetests =((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 False1 sha12 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; свой блок данных размером 0xA0ROM:01DBE844 MOV R4, R1ROM:01DBE848 LDR R1, =0x2105B04; тут лежат константыROM:01DBE84C MOV R5, R0ROM:01DBE850 LDMIA R1, {R1,R3,R12,LR}ROM:01DBE854 ADD R0, SP, #0x10ROM:01DBE858 STMIA R0, {R1,R3,R12,LR}; запишем себеROM:01DBE85C LDR R1, =0x2105B14; и тут константыROM:01DBE860 MOV R0, SPROM:01DBE864 LDMIA R1, {R1,R3,R12,LR}ROM:01DBE868 STMIA R0, {R1,R3,R12,LR}ROM:01DBE86C ADD R1, SP, #0x20ROM:01DBE870 ADD R0, SP, #0x10ROM:01DBE874 BL sub_1DBC554ROM:01DBE878 ADD R2, SP, #0x20 ROM:01DBE87C MOV R1, R4 ROM:01DBE880 MOV R0, R5 ROM:01DBE884 BL sub_1DBCEF0ROM:01DBE888 ADD SP, SP, #0xA0ROM: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, но переделывать всё не хочется, т.к. изменились адреса загрузки ядра, соответственно и все процедуры сдвинулись… Если есть желание можете пройти этот путь с новой прошивкой, думаю результат будет тот же.
ссылка на оригинал статьи https://habr.com/ru/articles/1064990/