разобрался с методом шифрования валкеры

итак. хочется для какой-нибудь поделки сделать модификацию, например, написать свой софт для мелкого квадрика, добавить привязку к спектруму. но существует шанс свой софт не дописать, а родной угробить. валкера выкладывает прошивки для некоторых своих поделок. например, для моей “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);
}
  • 2238
Comments
Робби

как всё сложно

Stanton

Просто красавчик! Мой профессор по криптографии автомат бы поставил 😃