kopia lustrzana https://github.com/sq5bpf/k5prog
Porównaj commity
14 Commity
6eb4ac3822
...
241ab18b61
Autor | SHA1 | Data |
---|---|---|
sq5bpf | 241ab18b61 | |
sq5bpf | e4b2c47d17 | |
sq5bpf | 350e667c5d | |
sq5bpf | 3eb6e144fc | |
sq5bpf | 990eeb60aa | |
sq5bpf | 767688f746 | |
sq5bpf | 4e6ebbc760 | |
Wouter van Gulik | c42c8b9f9d | |
Wouter van Gulik | 32b6d4bb9d | |
Bruno Rohée | 83e1118a41 | |
Bruno Rohée | bc02b2460c | |
Bruno Rohée | a3faca61d9 | |
Bruno Rohée | a9e37bbd50 | |
Bruno Rohée | 81db753247 |
58
README
58
README
|
@ -1,14 +1,14 @@
|
|||
k5prog - Quansheng UV-K5 EEPROM and flash programmer v0.9
|
||||
(c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||
|
||||
This program can read and write the eeprom of Quansheng UV-K5.
|
||||
This program can read and write the EEPROM of Quansheng UV-K5.
|
||||
It can read/write arbitrary data, and might be useful for making backups of
|
||||
the configuration, mass programming of radios or reverse engineering of
|
||||
the radio configuration. Please note that it is probably possible to break
|
||||
your radio by writing a bad configuration to it, so please use at your own
|
||||
risk.
|
||||
|
||||
Note that this program does not edit the contents of the eeprom. Use an
|
||||
Note that this program does not edit the contents of the EEPROM. Use an
|
||||
external hex editor.
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ here:
|
|||
https://github.com/fagci/qs-uvk5-firmware-modder
|
||||
An example decrypted file is provided in k5_flash_test.raw, this is the vendor
|
||||
2.01.23 firmware without any modifications.
|
||||
Please use extreme caution, as reprogramming the radioflash can potentially i
|
||||
Please use extreme caution, as reprogramming the radioflash can potentially
|
||||
brick your radio. If unsure, please use the vendor flashing software.
|
||||
|
||||
The flashing support in k5prog was used in at least 2 cases to recover radios
|
||||
|
@ -31,38 +31,38 @@ To compile, please see the compiling section at the end.
|
|||
|
||||
|
||||
The program is written to (hopefully) run on POSIX systems. Testing was done
|
||||
on GNU/Linux, but MacOS X and windows under cygwin should work too.
|
||||
on GNU/Linux, but macOS and Windows under Cygwin should work too.
|
||||
|
||||
For licensing see the file LICENSE.
|
||||
|
||||
|
||||
---- Usage ----
|
||||
|
||||
for help run the programwithout arguments, or with the -h option.
|
||||
to display help run the program without arguments, or with the -h option.
|
||||
|
||||
The configuration options are:
|
||||
Quansheng UV-K5 EEPROM programmer v0.8 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||
|
||||
cmdline opts:
|
||||
-f <file> filename that contains the eeprom dump (default: k5_eeprom.raw)
|
||||
-f <file> filename that contains the EEPROM dump (default: k5_eeprom.raw)
|
||||
-b <file> filename that contains the raw flash image (default k5_flash.raw)
|
||||
-Y increase "I know what i'm doing" value, to enable functionality likely to break the radio
|
||||
-Y increase "I know what I'm doing" value, to enable functionality likely to break the radio
|
||||
-D wait for the message from the radio flasher, print it's version
|
||||
-F flash firmware, WARNING: this will likely brick your radio!
|
||||
-M <ver> Set the firmware major version to <ver> during the flash process (default: *.01.23)
|
||||
-r read eeprom
|
||||
-w write eeprom like the original software does
|
||||
-W write most of the eeprom (but without what i think is calibration data)
|
||||
-B write ALL of the eeprom (the "brick my radio" mode)
|
||||
-r read EEPROM
|
||||
-w write EEPROM like the original software does
|
||||
-W write most of the EEPROM (but without what I think is calibration data)
|
||||
-B write ALL of the EEPROM (the "brick my radio" mode)
|
||||
-p <port> device name (default: /dev/ttyUSB0)
|
||||
-s <speed> serial speed (default: 38400, the UV-K5 doesn't accept any other speed)
|
||||
-h print this help
|
||||
-v be verbose, use multiple times for more verbosity
|
||||
|
||||
|
||||
---- Reading/writing the configuration eeprom ----
|
||||
---- Reading/writing the configuration EEPROM ----
|
||||
|
||||
For a basic usage use -r to read eeprom, -w to write eeprom. The -v option
|
||||
For a basic usage use -r to read EEPROM, -w to write EEPROM. The -v option
|
||||
gives more verbosity.
|
||||
|
||||
Read configuration:
|
||||
|
@ -72,10 +72,10 @@ Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowsk
|
|||
|
||||
k5_prepare: try 0
|
||||
****** Connected to firmware version: [k5_2.01.23]
|
||||
Sucessfuly read eeprom
|
||||
Successfully read EEPROM
|
||||
|
||||
|
||||
The eeprom contents are written to the file k5_eeprom.raw, this can be
|
||||
The EEPROM contents are written to the file k5_eeprom.raw, this can be
|
||||
changed with the -f option.
|
||||
|
||||
|
||||
|
@ -87,14 +87,14 @@ Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowsk
|
|||
k5_prepare: try 0
|
||||
****** Connected to firmware version: [k5_2.01.23]
|
||||
Read file k5_eeprom.raw success
|
||||
Sucessfuly wrote eeprom
|
||||
Successfully wrote EEPROM
|
||||
|
||||
|
||||
|
||||
The -w option writes only the memory blocks which are written by the original
|
||||
radio software, in the same order.
|
||||
|
||||
The -W option is a bit more brave, it writes all memory upto 0x1d00. I _think_
|
||||
The -W option is a bit braver as it writes all memory upto 0x1d00. I _think_
|
||||
that the radio has calibration data above this address, but of course this is
|
||||
not certain, because this knowledge is a result of reverse engineering, and not
|
||||
information from the manufacturer.
|
||||
|
@ -105,7 +105,7 @@ allowing overwriting of calibration data (if there is any) or other data which
|
|||
may be critical to the proper functioning of your radio. I have used this on
|
||||
my radio, and it still works but please be extra-careful.
|
||||
|
||||
I have written the radio eeprom with the -W option tens of times, and others
|
||||
I have written the radio EEPROM with the -W option tens of times, and others
|
||||
have too. So far it hasn't produced any bad results. But of course beware.
|
||||
|
||||
|
||||
|
@ -114,14 +114,14 @@ have too. So far it hasn't produced any bad results. But of course beware.
|
|||
The flashing support is for the really brave people who know what they are
|
||||
doing (hence the -Y flag is needed).
|
||||
|
||||
It is possible to read the bootloder version using the -D option. This option
|
||||
It is possible to read the bootloader version using the -D option. This option
|
||||
is safe, but needs the -Y value. Put the radio into flash mode and:
|
||||
|
||||
./k5prog -Y -D
|
||||
|
||||
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||
|
||||
"I know what i'm doing" value set to 1
|
||||
"I know what I'm doing" value set to 1
|
||||
******** k5 command hexdump [obf_len:44 clear_len:36 crc_ok:1 **********
|
||||
## obfuscated ##
|
||||
|
||||
|
@ -143,13 +143,13 @@ Flasher version is: [2.00.06]
|
|||
The radio can also be flashed with the raw unencrypted binary.
|
||||
An example binary is provided in the k5_flash.raw file (this is the 2.01.23
|
||||
firmware). The binary file can be specified with the -b option.
|
||||
Flashing the radio requires the "i know what i'm doing value" of at least 5.
|
||||
Flashing the radio requires the "I know what I'm doing value" of at least 5.
|
||||
|
||||
./k5prog -b k5_flash.raw -YYYYYY -F
|
||||
|
||||
Quansheng UV-K5 EEPROM programmer v0.5 (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||
|
||||
"I know what i'm doing" value set to 6
|
||||
"I know what I'm doing" value set to 6
|
||||
******** k5 command hexdump [obf_len:44 clear_len:36 crc_ok:1 **********
|
||||
## obfuscated ##
|
||||
|
||||
|
@ -190,19 +190,19 @@ simple makefile:
|
|||
sq5bpf@dellix:~/k5prog-0.1$ make
|
||||
gcc -O2 k5prog.c -o k5prog
|
||||
|
||||
Other POSIX platforms should work also, including MacOS X.
|
||||
Other POSIX platforms should work also, including macOS.
|
||||
|
||||
The software compiles under Cygwin/Microsoft Windows, but has not been tested.
|
||||
According to the cygwin documentation you should use /dev/comX to use port comX
|
||||
According to the Cygwin documentation you should use /dev/comX to use port comX
|
||||
(for example using com6: k5prog.exe -v -r -p /dev/com6)
|
||||
|
||||
|
||||
If port this to another platform, or do anything interesting with this
|
||||
If you port this to another platform, or do anything interesting with this
|
||||
software, tell me about it.
|
||||
|
||||
---- Other uses ----
|
||||
|
||||
The file uvk5_original_eeprom.raw contains an eeprom downloaded from a UV-K5
|
||||
The file uvk5_original_eeprom.raw contains an EEPROM downloaded from an UV-K5
|
||||
radio. Maybe it can be used to resurrect another radio of the same type
|
||||
if it was broken (perhaps by the use of this software :).
|
||||
|
||||
|
@ -220,13 +220,13 @@ The format of the datagram sent to the radio is:
|
|||
|
||||
0xAB 0xCD len 0x00 <data bytes> <2 bytes CRC> 0xDC 0xBA
|
||||
|
||||
The length is the length od the data bytes.
|
||||
The length is the length of the data bytes.
|
||||
|
||||
The data is protected by a typical CRC-16 xmodem algorithm.
|
||||
The data bytes and the CRC are obfuscated by xor-in it with an 8-byte
|
||||
sequence.
|
||||
|
||||
Fortunately the eeprom data contains a lot of 0xFF and 0x00 bytes, so the XOR
|
||||
Fortunately the EEPROM data contains a lot of 0xFF and 0x00 bytes, so the XOR
|
||||
sequence is easy to find by observing the traffic.
|
||||
|
||||
|
||||
|
@ -235,7 +235,7 @@ The datagram sent from the radio is the same, but the CRC field is set to
|
|||
obfuscation (same as the XOR).
|
||||
|
||||
|
||||
I intend to publish a further description of the protocol, and the eeprom
|
||||
I intend to publish a further description of the protocol, and the EEPROM
|
||||
contents, meanwhile the sources can be used as documentation.
|
||||
|
||||
|
||||
|
|
86
k5prog.c
86
k5prog.c
|
@ -1,7 +1,7 @@
|
|||
/* Quansheng UV-K5 EEPROM programmer v0.9
|
||||
* (c) 2023 Jacek Lipkowski <sq5bpf@lipkowski.org>
|
||||
*
|
||||
* This program can read and write the eeprom of Quansheng UVK5 Mark II
|
||||
* This program can read and write the EEPROM of Quansheng UVK5 Mark II
|
||||
* and probably other similar radios via the serial port.
|
||||
*
|
||||
* It can read/write arbitrary data, and might be useful for reverse
|
||||
|
@ -110,8 +110,8 @@ unsigned char uvk5_hello2[]={0x14, 0x05, 0x04, 0x00, 0x9f, 0x25, 0x5a, 0x64};
|
|||
|
||||
/* commands:
|
||||
* 0x14 - hello
|
||||
* 0x1b - read eeprom
|
||||
* 0x1d - write eeprom
|
||||
* 0x1b - read EEPROM
|
||||
* 0x1d - write EEPROM
|
||||
* 0xdd - reset radio
|
||||
*/
|
||||
|
||||
|
@ -229,6 +229,13 @@ int read_timeout(int fd, unsigned char *buf, int maxlen, int timeout)
|
|||
|
||||
ret=select(fd+1,&rfd,0,0,&tv);
|
||||
|
||||
if (ret==0) {
|
||||
if(timeout) /* Only print if we requested a timeout */
|
||||
fprintf(stderr,"read_timeout\n");
|
||||
/* error or timeout */
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd,&rfd)) {
|
||||
nr=read(fd,buf,maxlen);
|
||||
|
||||
|
@ -236,17 +243,9 @@ int read_timeout(int fd, unsigned char *buf, int maxlen, int timeout)
|
|||
buf=buf+nr;
|
||||
if (nr>=0) maxlen=maxlen-nr;
|
||||
if (maxlen==0) break;
|
||||
}
|
||||
|
||||
|
||||
if (ret==0) {
|
||||
fprintf(stderr,"read_timeout\n");
|
||||
/* error albo timeout */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (verbose>2) {
|
||||
if (verbose>2 && len > 0) {
|
||||
printf("RXRXRX:\n");
|
||||
hdump(buf2,len);
|
||||
}
|
||||
|
@ -427,11 +426,22 @@ struct k5_command *k5_receive(int fd,int tmout) {
|
|||
return(0);
|
||||
}
|
||||
|
||||
/* During plugging in etc we can receive a single byte.
|
||||
* Handle this case here. */
|
||||
if (len != sizeof(buf))
|
||||
{
|
||||
fprintf(stderr,"k5_receive: got %d expected %ld\n", len, sizeof(buf));
|
||||
return(0);
|
||||
}
|
||||
|
||||
if ((buf[0]!=0xab)||(buf[1]!=0xcd)) {
|
||||
fprintf(stderr,"k5_receive: bad magic number\n");
|
||||
return(0);
|
||||
}
|
||||
if ((buf[0]!=0xab)||(buf[1]!=0xcd)) {
|
||||
fprintf(stderr,"k5_receive: bad magic number\n");
|
||||
/* Assume we are out of sync and flush rx buffer by reading everything.
|
||||
* This works because the boot message is repeated. */
|
||||
while (len>0)
|
||||
len =read_timeout(fd,(unsigned char *)&buf,sizeof(buf),10000);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (buf[3]!=0) {
|
||||
fprintf(stderr,"k5_receive: it seems that byte 3 can be something else than 0, please notify the author\n");
|
||||
|
@ -455,7 +465,7 @@ struct k5_command *k5_receive(int fd,int tmout) {
|
|||
return(cmd);
|
||||
}
|
||||
/******************************/
|
||||
/* eeprom read/write support */
|
||||
/* EEPROM read/write support */
|
||||
/******************************/
|
||||
int k5_readmem(int fd, unsigned char *buf, unsigned char maxlen, int offset)
|
||||
{
|
||||
|
@ -542,7 +552,7 @@ int k5_reset(int fd)
|
|||
r=k5_send_buf(fd,uvk5_reset,sizeof(uvk5_reset));
|
||||
return(r);
|
||||
}
|
||||
/* end of eeprom read/write support */
|
||||
/* end of EEPROM read/write support */
|
||||
|
||||
|
||||
/******************************/
|
||||
|
@ -564,8 +574,9 @@ int wait_flash_message(int fd,int ntimes) {
|
|||
cmd=k5_receive(fd,10000);
|
||||
|
||||
if (!cmd) {
|
||||
printf("wait_flash_message: timeout\n");
|
||||
continue;
|
||||
/* No need to print, k5_receive already printed why it failed */
|
||||
//printf("wait_flash_message: timeout\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
k5_hexdump(cmd);
|
||||
|
@ -576,8 +587,8 @@ int wait_flash_message(int fd,int ntimes) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (cmd->cmd[0]!=0x18) {
|
||||
printf("wait_flash_message: got unexpected command type 0x%2.2x\n",cmd->cmd[0]);
|
||||
if ((cmd->cmd[0]!=0x18)&&(cmd->cmd[1]!=0x05)) {
|
||||
printf("wait_flash_message: got unexpected command type 0x%2.2x 0x%2.2x\n",cmd->cmd[1],cmd->cmd[0]);
|
||||
destroy_k5_struct(cmd);
|
||||
continue;
|
||||
}
|
||||
|
@ -600,11 +611,6 @@ int wait_flash_message(int fd,int ntimes) {
|
|||
* 0x000020: 00 00 00 20 ...
|
||||
*/
|
||||
|
||||
if ((cmd->cmd[2]!=0x20)||(cmd->cmd[3]!=0x0)||(cmd->cmd[4]!=0x1)||(cmd->cmd[5]!=0x2)||(cmd->cmd[6]!=0x2)) {
|
||||
printf("wait_flash_message: got unexpected packet contents\n");
|
||||
destroy_k5_struct(cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* all is good, so break */
|
||||
ok=1; break;
|
||||
|
@ -748,14 +754,14 @@ void helpme()
|
|||
"cmdline opts:\n"
|
||||
"-f <file>\tfilename that contains the eeprom dump (default: " DEFAULT_FILE_NAME ")\n"
|
||||
"-b <file>\tfilename that contains the raw flash image (default " DEFAULT_FLASH_NAME ")\n"
|
||||
"-Y \tincrease \"I know what i'm doing\" value, to enable functionality likely to break the radio\n"
|
||||
"-Y \tincrease \"I know what I'm doing\" value, to enable functionality likely to break the radio\n"
|
||||
"-D \twait for the message from the radio flasher, print it's version\n"
|
||||
"-F \tflash firmware, WARNING: this will likely brick your radio!\n"
|
||||
"-M <ver> \tSet the firmware major version to <ver> during the flash process (default: " DEFAULT_FLASH_VERSION ")\n"
|
||||
"-r \tread eeprom\n"
|
||||
"-w \twrite eeprom like the original software does\n"
|
||||
"-W \twrite most of the eeprom (but without what i think is calibration data)\n"
|
||||
"-B \twrite ALL of the eeprom (the \"brick my radio\" mode)\n"
|
||||
"-W \twrite most of the EEPROM (but without what I think is calibration data)\n"
|
||||
"-B \twrite ALL of the EEPROM (the \"brick my radio\" mode)\n"
|
||||
"-p <port>\tdevice name (default: " DEFAULT_SERIAL_PORT ")\n"
|
||||
"-s <speed>\tserial speed (default: 38400, the UV-K5 doesn't accept any other speed)\n"
|
||||
"-h \tprint this help\n"
|
||||
|
@ -929,6 +935,14 @@ int k5_prepare(int fd) {
|
|||
cmd=k5_receive(fd,10000);
|
||||
if (!cmd) return(0);
|
||||
|
||||
/* this is a bit problem with people trying to read the radio config in firmware flash mode,
|
||||
* don't know why people do this, but they do it quite often */
|
||||
if ((cmd->cmd[0]==0x18)&&(cmd->cmd[1]==0x05)) {
|
||||
fprintf(stderr,"\nWARNING: this radio is in firmware flash mode (PTT + turn on).\n"
|
||||
"Please have the radio in normal mode to read the EEPROM\n\n");
|
||||
return(0);
|
||||
}
|
||||
printf ("cmd: %2.2x %2.2x ok:%i\n",cmd->cmd[0],cmd->cmd[1],cmd->crcok);
|
||||
printf("****** Connected to firmware version: [%s]\n",(cmd->cmd)+4);
|
||||
destroy_k5_struct(cmd);
|
||||
|
||||
|
@ -990,7 +1004,7 @@ int main(int argc,char **argv)
|
|||
|
||||
ffd=open(flash_file,O_RDONLY);
|
||||
if (ffd<0) {
|
||||
fprintf(stderr,"open %s error %d %s\n", file, errno, strerror(errno));
|
||||
fprintf(stderr,"open %s error %d %s\n", flash_file, errno, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
flash_length=read(ffd,(unsigned char *)&flash,UVK5_MAX_FLASH_SIZE);
|
||||
|
@ -998,7 +1012,7 @@ int main(int argc,char **argv)
|
|||
|
||||
/* arbitrary limit do that someone doesn't flash some random short file */
|
||||
if ((i_know_what_im_doing<5)&&(flash_length<50000)) {
|
||||
fprintf(stderr,"Failed to read whole eeprom from file %s (read %i), file too short or some other error\n",file,flash_length);
|
||||
fprintf(stderr,"Failed to read whole EEPROM from file %s (read %i), file too short or some other error\n",file,flash_length);
|
||||
if (flash_length>0) {
|
||||
fprintf(stderr,"This failsafe is here so that people don't mistake config files with flash.\nIt can be ignored with an 'i know what i'm doing' value of at least 5\n");
|
||||
}
|
||||
|
@ -1079,7 +1093,7 @@ int main(int argc,char **argv)
|
|||
}
|
||||
}
|
||||
close(fd);
|
||||
if (verbose>0) { printf("\rSucessfuly read eeprom\n"); }
|
||||
if (verbose>0) { printf("\rSuccessfully read EEPROM\n"); }
|
||||
if (verbose>2) { hdump((unsigned char *)&eeprom,UVK5_EEPROM_SIZE); }
|
||||
|
||||
write_file(file,(unsigned char *)&eeprom,UVK5_EEPROM_SIZE);
|
||||
|
@ -1090,7 +1104,7 @@ int main(int argc,char **argv)
|
|||
case MODE_WRITE_MOST:
|
||||
case MODE_WRITE_ALL:
|
||||
if ((mode==MODE_WRITE_ALL)&&(i_know_what_im_doing<1)) {
|
||||
printf("ERROR: the \"I know what i'm doing\" value has to be at least 1 to confirm that you know what you're doing\n");
|
||||
printf("ERROR: the \"I know what I'm doing\" value has to be at least 1 to confirm that you know what you're doing\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -1102,7 +1116,7 @@ int main(int argc,char **argv)
|
|||
}
|
||||
r=read(ffd,(unsigned char *)&eeprom[i],UVK5_EEPROM_SIZE);
|
||||
if (r!=UVK5_EEPROM_SIZE) {
|
||||
fprintf(stderr,"Failed to read whole eeprom from file %s, file too short?\n",file);
|
||||
fprintf(stderr,"Failed to read whole EEPROM from file %s, file too short?\n",file);
|
||||
exit(1);
|
||||
}
|
||||
close(ffd);
|
||||
|
@ -1146,7 +1160,7 @@ int main(int argc,char **argv)
|
|||
}
|
||||
}
|
||||
k5_reset(fd);
|
||||
if (verbose>0) { printf("\rSucessfuly wrote eeprom\n"); }
|
||||
if (verbose>0) { printf("\rSuccessfully wrote EEPROM\n"); }
|
||||
|
||||
|
||||
break;
|
||||
|
|
2
uvk5.h
2
uvk5.h
|
@ -1,4 +1,4 @@
|
|||
/* UV-K5 eeprom programmer */
|
||||
/* UV-K5 EEPROM programmer */
|
||||
|
||||
#ifndef UVK5_INCLUDE_H
|
||||
#define UVK5_INCLUDE_H
|
||||
|
|
Ładowanie…
Reference in New Issue