разобрался с методом шифрования валкеры
итак. хочется для какой-нибудь поделки сделать модификацию, например, написать свой софт для мелкого квадрика, добавить привязку к спектруму. но существует шанс свой софт не дописать, а родной угробить. валкера выкладывает прошивки для некоторых своих поделок. например, для моей “new v120d02s” есть обновление прошивки. но они зашифрованы. а bootloader мы уже потерли своими экспериментами и не можем прошить зашифрованный бинарник. решил я на досуге посмотреть чего можно сделать.
смотрим в шифрованный бинарник, в начале файла много повторяющихся байт. это JMP table. значит файл зашифрован слабо.
внутри стоит хмега32а4, собираем компилятором winAVR любой код под этот процессор. в начале бинарника идет таблица JMP для прерываний. т.е. если примем байт в УАРТ, то процессор сделает переход по этой таблице.
первые байты представляют из себя jmp _reset_vector, который ведет в код начальной инициализации. остальные, если вектор не используется, то по идее тоже на вектор сброса. смотрим код и рядом дизасм его:
00: 0C 94 BC 00 jmp 0x00BC
02: 0C 94 DD 00 jmp 0x00DD
теперь смотрим в шифрованный бинарь, видны повторяющиеся строки в jmp table. предположим, что используется обычный оператор XOR, получим начальные байты ключа. т.к. первые байты команды будут гарантировано 0C 94. адреса пока оставим как есть. сделаем допущение, что адрес будет состоять из одного байта, старший байт нулевой. наполняем табличку которой будем построчно XOR файл.
unsigned char XOR[16]={0x89, 0xc7, 0, 0xb4, 0xdf, 0x65, 0, 0xa1, 0xb7, 0xca, 0, 0x0c, 0x70, 0x33, 0, 0xba};
дизассемблируем полурасшифрованный бинарник. таблица переходов расшифровалась, но адреса пока в виде мусора и часть команд в виде мусора. значит идея работает. надо получить остаток ключа.
смотрим в код сгенереный компилятором. точнее в точку куда ведет jmp reset_vector
это известный мне файл
+000000BC: 2411 CLR R1 Clear Register
+000000BD: BE1F OUT 0x3F,R1 Out to I/O location
+000000BE: EFCF SER R28 Set Register
+000000BF: E2DF LDI R29,0x2F Load immediate
+000000C0: BFDE OUT 0x3E,R29 Out to I/O location
+000000C1: BFCD OUT 0x3D,R28 Out to I/O location
+000000C2: BE18 OUT 0x38,R1 Out to I/O location
+000000C3: BE19 OUT 0x39,R1 Out to I/O location
+000000C4: BE1A OUT 0x3A,R1 Out to I/O location
+000000C5: BE1B OUT 0x3B,R1 Out to I/O location
+000000C6: E211 LDI R17,0x21 Load immediate
+000000C7: E0A0 LDI R26,0x00 Load immediate
+000000C8: E2B0 LDI R27,0x20 Load immediate
+000000C9: E2E0 LDI R30,0x20 Load immediate
+000000CA: E0FF LDI R31,0x0F Load immediate
это то что дизассемблер сделал из полурасшифрованного файла
+000000E2: 1A7F SUB R7,R31 Subtract without carry
+000000E3: 7232 ANDI R19,0x22 Logical AND with immediate
+000000E4: 2411 CLR R1 Clear Register
+000000E5: BE40 OUT 0x30,R4 Out to I/O location
+000000E6: EFCF SER R28 Set Register
+000000E7: E266 LDI R22,0x26 Load immediate
+000000E8: BFDE OUT 0x3E,R29 Out to I/O location
+000000E9: BFEB OUT 0x3B,R30 Out to I/O location
+000000EA: BE18 OUT 0x38,R1 Out to I/O location
+000000EB: BE3F OUT 0x3F,R3 Out to I/O location
+000000EC: BE1A OUT 0x3A,R1 Out to I/O location
+000000ED: BE44 OUT 0x34,R4 Out to I/O location
+000000EE: E212 LDI R17,0x22 Load immediate
+000000EF: E019 LDI R17,0x09 Load immediate
+000000F0: E2B0 LDI R27,0x20 Load immediate
+000000F1: E3C2 LDI R28,0x32 Load immediate
+000000F2: E6F1 LDI R31,0x61 Load immediate
опа, среди мусора нашлись похожие команды, ведь кроме части таблицы расшифровалась и часть кода. и даже команда CLR R1 видна. записываем адрес этой команды 0x00E4.
теперь поищем куда ведет переход с неиспользуемого прерывания. у нас это адрес 0x00DD
+000000D6: 3EAD CPI R26,0xED Compare with immediate
+000000D7: 07B1 CPC R27,R17 Compare with carry
+000000D8: F7E1 BRNE PC-0x03 Branch if not equal
+000000D9: 940E018B CALL 0x0000018B Call subroutine
+000000DB: 940C078E JMP 0x0000078E Jump
+000000DD: 940C0000 JMP 0x00000000 Jump
+000000DF: 94F8 CLI Global Interrupt Disable
+000000E0: E8E1 LDI R30,0x81 Load immediate
а вот в похожий код
+00000100: F7E1 BRNE PC-0x03 Branch if not equal
+00000101: 9428 SEN Set Negative Flag
+00000102: 29FF OR R31,R15 Logical OR
+00000103: 942A DEC R2 Decrement
+00000104: 2D7C MOV R23,R12 Copy register
+00000105: 9453 INC R5 Increment
+00000106: 0000 NOP No operation
+00000107: 93B6 LAC R27 Load and Clear
+00000108: 93DF PUSH R29 Push register on stack
в мусорном коде находим последовательность байт 94 через нужное нам расстояние, это очень похоже на то, что надо. и даже видим 00 00, это адрес куда будет совершен переход. записываем адрес этой команды, 0x0105.
дописываем адреса
00: 0C 94 E4 00 jmp 0x00E4
02: 0C 94 05 01 jmp 0x0105
04: 0C 94 05 01 jmp 0x0105
06: 0C 94 05 01 jmp 0x0105
08: 0C 94 05 01 jmp 0x0105
и так всю строку до конца. получаем оставшиеся ключи
unsigned char XOR[16]={0x89, 0xc7, 0x26, 0xb4, 0xdf, 0x65, 0x26, 0xa1, 0xb7, 0xca, 0x5f, 0x0c, 0x70, 0x33, 0xb9, 0xba};
обрабатываем зашифрованный файл и суем его в дизассемблер.
ага. таблица переходов расшифровалась, код куда ведут эти jmp тоже похож на скомпилированный. проверяем куда ведут jmp векторов прерываний, убеждаемся, что в начале этих процедур стоит много push register, а в конце pop register и IRET.
вуаля.
теперь код, которым надо зашифровать свой бинарник, чтобы встроенный bootloader его принял за свой:
#include <stdio.h>
void main(void){
FILE *fp_input, *fp_output;
unsigned char buffer[16];
//for
unsigned char XOR[16]={0x89, 0xc7, 0x26, 0xb4, 0xdf, 0x65, 0x26, 0xa1, 0xb7, 0xca, 0x5f, 0x0c, 0x70, 0x33, 0xb9, 0xba};
int i, c;
fp_input=fopen("input.bin", "rb");
fp_output=fopen("output.bin", "wb");
for(i = 0; i < 1590; i++){
fread(buffer, sizeof(buffer[0]), 16, fp_input);
for(c = 0; c < 16; c++){
buffer[c] ^= XOR[c];
}
fwrite(buffer, sizeof(buffer[0]), 16, fp_output);
}
fclose(fp_input);
fclose(fp_output);
}