Skip to content

Commit 87a565c

Browse files
committed
WIP: Add firmware decryption
1 parent 6eb4ac3 commit 87a565c

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

k5prog.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,114 @@ int k5_prepare(int fd) {
935935
return(1);
936936
}
937937

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

1107+
bool success = decrypt(flash, &flash_length);
1108+
if (!success) {
1109+
exit(1);
1110+
}
1111+
9991112
/* arbitrary limit do that someone doesn't flash some random short file */
10001113
if ((i_know_what_im_doing<5)&&(flash_length<50000)) {
10011114
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)