Постановка задачи
Есть устройство, работает с чипами 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, но переделывать всё не хочется, т.к. изменились адреса загрузки ядра, соответственно и все процедуры сдвинулись… Если есть желание можете пройти этот путь с новой прошивкой, думаю результат будет тот же.
hddscan
У IDA есть декомпилятор для АРМ-а, сильно упрощает понимание кода.
Koluchy
А findcrypt и ему подобные плагины отлично помогают в идентификации криптоалгоритмов...
pMalice Автор
Соглашусь. Но эмуляция позволяет получить результат функции до анализа алгоритма, дает понимание конечного результата. Очень полезный инструмент.