Skip to content

Commit 2bd2423

Browse files
committed
WIP: Add firmware decryption
copy pasted and adapted from https://github.com/OneOfEleven/k5prog-win
1 parent 6eb4ac3 commit 2bd2423

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

k5prog.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <string.h>
4343
#include <errno.h>
4444
#include <stdlib.h>
45+
#include <stdbool.h>
4546
#include <termios.h>
4647
#include <unistd.h>
4748
#include <stdio.h>
@@ -935,6 +936,114 @@ int k5_prepare(int fd) {
935936
return(1);
936937
}
937938

939+
#define CRC_POLY16 0x1021
940+
// slow bit-bang based
941+
// https://github.com/OneOfEleven/k5prog-win/blob/a8af838b91bf17027179881accc1701949d66a0b/Unit1.cpp#L1192C2-L1192C2
942+
uint16_t crc16(const uint8_t *data, const int size)
943+
{
944+
uint16_t crc = 0;
945+
if (data != NULL && size > 0)
946+
{
947+
for (int i = 0; i < size; i++)
948+
{
949+
crc ^= (uint16_t)data[i] << 8;
950+
for (unsigned int k = 8; k > 0; k--)
951+
crc = (crc & 0x8000) ? (crc << 1) ^ CRC_POLY16 : crc << 1;
952+
}
953+
}
954+
return crc;
955+
}
956+
957+
// (de)obfuscate firmware data
958+
// https://github.com/OneOfEleven/k5prog-win/blob/a8af838b91bf17027179881accc1701949d66a0b/Unit1.cpp#L1456
959+
void k5_xor_firmware(uint8_t *data, const int len)
960+
{
961+
static const uint8_t xor_pattern[] =
962+
{
963+
0x47, 0x22, 0xc0, 0x52, 0x5d, 0x57, 0x48, 0x94, 0xb1, 0x60, 0x60, 0xdb, 0x6f, 0xe3, 0x4c, 0x7c,
964+
0xd8, 0x4a, 0xd6, 0x8b, 0x30, 0xec, 0x25, 0xe0, 0x4c, 0xd9, 0x00, 0x7f, 0xbf, 0xe3, 0x54, 0x05,
965+
0xe9, 0x3a, 0x97, 0x6b, 0xb0, 0x6e, 0x0c, 0xfb, 0xb1, 0x1a, 0xe2, 0xc9, 0xc1, 0x56, 0x47, 0xe9,
966+
0xba, 0xf1, 0x42, 0xb6, 0x67, 0x5f, 0x0f, 0x96, 0xf7, 0xc9, 0x3c, 0x84, 0x1b, 0x26, 0xe1, 0x4e,
967+
0x3b, 0x6f, 0x66, 0xe6, 0xa0, 0x6a, 0xb0, 0xbf, 0xc6, 0xa5, 0x70, 0x3a, 0xba, 0x18, 0x9e, 0x27,
968+
0x1a, 0x53, 0x5b, 0x71, 0xb1, 0x94, 0x1e, 0x18, 0xf2, 0xd6, 0x81, 0x02, 0x22, 0xfd, 0x5a, 0x28,
969+
0x91, 0xdb, 0xba, 0x5d, 0x64, 0xc6, 0xfe, 0x86, 0x83, 0x9c, 0x50, 0x1c, 0x73, 0x03, 0x11, 0xd6,
970+
0xaf, 0x30, 0xf4, 0x2c, 0x77, 0xb2, 0x7d, 0xbb, 0x3f, 0x29, 0x28, 0x57, 0x22, 0xd6, 0x92, 0x8b
971+
};
972+
973+
if (data == NULL || len <= 0)
974+
return;
975+
976+
for (int i = 0; i < len; i++)
977+
data[i] ^= xor_pattern[i % sizeof(xor_pattern)];
978+
}
979+
980+
// https://github.com/OneOfEleven/k5prog-win/blob/a8af838b91bf17027179881accc1701949d66a0b/Unit1.cpp#L2663
981+
bool decrypt(unsigned char *flash, int *flash_size) {
982+
983+
bool encrypted = true;
984+
985+
const uint16_t crc1 = crc16(&flash[0], *flash_size - 2);
986+
const uint16_t crc2 = ((uint16_t)flash[*flash_size - 1] << 8) | ((uint16_t)flash[*flash_size - 2] << 0);
987+
988+
if (flash[ 2] == 0x00 &&
989+
flash[ 3] == 0x20 &&
990+
flash[ 6] == 0x00 &&
991+
flash[10] == 0x00 &&
992+
flash[14] == 0x00) {
993+
encrypted = false;
994+
}
995+
996+
if (encrypted && crc1 == crc2)
997+
{ // the file appears to be encrypted
998+
999+
// drop the 16-bit CRC
1000+
*flash_size = *flash_size - 2;
1001+
1002+
// decrypt it
1003+
k5_xor_firmware(&flash[0], *flash_size);
1004+
1005+
if (flash[ 2] == 0x00 &&
1006+
flash[ 3] == 0x20 &&
1007+
flash[ 6] == 0x00 &&
1008+
flash[10] == 0x00 &&
1009+
flash[14] == 0x00) {
1010+
encrypted = false;
1011+
}
1012+
1013+
if (!encrypted)
1014+
{
1015+
fprintf(stdout, "firmware file de-obfuscated\n");
1016+
}
1017+
1018+
if (!encrypted && *flash_size >= (0x2000 + 16))
1019+
{ // extract and remove the 16-byte version string
1020+
1021+
char firmware_ver[17] = {0};
1022+
memcpy(firmware_ver, &flash[0x2000], 16);
1023+
1024+
if (*flash_size > (0x2000 + 16))
1025+
memmove(&flash[0x2000], &flash[0x2000 + 16], *flash_size - 0x2000 - 16);
1026+
*flash_size = (*flash_size - 16);
1027+
1028+
if (strlen(firmware_ver) > 8) {
1029+
fprintf(stderr, "Firmware version unexpectedly long (%ld): %s\n", strlen(firmware_ver), firmware_ver);
1030+
return false;
1031+
}
1032+
strncpy(flash_version_string, firmware_ver, 8);
1033+
1034+
fprintf(stdout, "firmware file version '%s'\n", flash_version_string);
1035+
}
1036+
}
1037+
1038+
if (encrypted)
1039+
{
1040+
fprintf(stderr,"File doesn't appear to be valid for uploading\n");
1041+
return false;
1042+
}
1043+
1044+
return true;
1045+
}
1046+
9381047
int main(int argc,char **argv)
9391048
{
9401049
int fd,ffd;
@@ -996,6 +1105,11 @@ int main(int argc,char **argv)
9961105
flash_length=read(ffd,(unsigned char *)&flash,UVK5_MAX_FLASH_SIZE);
9971106
close(ffd);
9981107

1108+
bool success = decrypt(flash, &flash_length);
1109+
if (!success) {
1110+
exit(1);
1111+
}
1112+
9991113
/* arbitrary limit do that someone doesn't flash some random short file */
10001114
if ((i_know_what_im_doing<5)&&(flash_length<50000)) {
10011115
fprintf(stderr,"Failed to read whole eeprom from file %s (read %i), file too short or some other error\n",file,flash_length);

0 commit comments

Comments
 (0)