I'm continuing this discussion from https://forum.openwrt.org/viewtopic.php?id=37002 because it is no longer HAME specific. Go read my posts on pages 15-16 to see the discussion leading up to this. The short story is that the Poray (and MPR) devices use an encrypted/obfuscated firmware for factory upgrades. This is a pain because it means we can't flash OpenWRT from the factory web app. Until now.
This code is a packtool intended to take an OpenWRT (or other) kernel uImage (e.g. openwrt-xxx-sysupgrade.bin) and pack it into the format expected by the web admin tool in those devices.
This is presently USE AT YOUR OWN RISK! Meaning that unless you have a serial connection, it's probably not worth trying just yet. This is because you could potentially write a bad kernel and "soft" brick your router. UBoot will still be alive, so it's only considered a soft brick - it can be recovered by using serial connection to reflash via UBoot.
That being said.. I just successfully packed a customized Openwrt build into a "factory" image for MPR-L8 (HAME A1 clone) and used it to update a virgin MPR-L8 from the factory software. Worked first try!. The tool has been verified to generate binary identical images (from an unpack/pack round trip) on MPR-L8, Poray: M3, Q3, X5/X6, R50x, and X8.
One important note: If you're watching in the serial console, you may see some scary messages after flash:
SQUASHFS error: sb_bread failed reading block 0x697
SQUASHFS error: Unable to read page, block 1a1f26, size 3f50
SQUASHFS error: sb_bread failed reading block 0x697
SQUASHFS error: Unable to read page, block 1a1f26, size 3f50
and so on and so on. It looks like the factory software attempts some sort of verify after write that just fails miserably due to the new filesystem not matching the old one. But although the device was blinking it's solid red + slow blue blink of death, upon power cycling it booted the newly-flashed OpenWRT perfectly.
I was also successful in using UBoot to flash a decrypted factory software from the previously released unpack tool in order to restore an OpenWRT device back to factory software. So if you later decide you want your old software back, you can do it with a serial console at least. (Or maybe LuCi, but that fat bitch doesn't yet fit in 4MB so it might be a moot point).
At any rate, here's the tool. I'd like to enlist some users of various Poray devices (with a serial connection, of course) to act as beta testers:
1) Start with factory firmware, then pack a known good OpenWRT build for your device and attempt upgrading via the original factory web admin interface. If possible, also have the serial port connected and capturing, to give us some postmortem if it bombs.
2) Report back success or failure. No need for long serial dumps if it works, but please include them if it bricks.
3) Include any general comments about the tool or your experience. What do we need to do to make it noob-friendly?
Good luck, and I wish you easy success in liberating your devices from factory tyranny!
Usage: pack <device> <infile> <outfile>
Example: pack PM3 OpenWRT.bin Poray_M3_OpenWRT.bin
/************************************************************************************
* Router firmware packing tool
* Copyright (c) 2013 openschemes.com and Michel Stempin <michel.stempin@wanadoo.fr>
***********************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
uint32_t magic;
uint32_t len;
uint32_t imgflags;
uint32_t junk[4];
} fheader;
int main(int argc, char *argv[])
{
char *infname;
char *outfname;
char *device;
FILE* infile;
FILE* outfile;
uint32_t checksum, mychecksum;
uint32_t i;
fheader f;
uint8_t MPRkey[] = {0xC8, 0x3C, 0x3A, 0x93, 0xA2, 0x95, 0xC3, 0x63, 0x48, 0x45, 0x58, 0x09, 0x12, 0x03, 0x08};
uint8_t PORkey[] = {0x89, 0x6B, 0x5A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7};
uint8_t PO2key[] = {0x79, 0x7B, 0x7A, 0x93, 0x92, 0x95, 0xC3, 0x63, 0xD0, 0xA3, 0x9C, 0x92, 0x2E, 0xE6, 0xC7};
uint8_t mykey[15];
uint8_t *data; //Pointer to our big data array
printf("===============================================================\n");
printf(" PACK - Encrypt and prepare Linux image for router firmware\n");
printf(" (C) 2013 Michel Stempin <michel.stempin@wanadoo.fr>\n");
printf(" (C) 2013 www.openschemes.com\n");
printf("===============================================================\n\n");
//Check arguments
if (argc > 3)
{
device = argv[1];
printf("Device: %s\n", device);
infname = argv[2];
printf("Input File: %s\n", infname);
outfname = argv[3];
printf("Output File: %s\n", outfname);
}
else
{
printf("Wrong number of arguments.\n");
printf("Usage: %s device inputfile outputfile\n", argv[0]);
printf("Choices for <device> Case sensitive!\n");
printf("PM3 - Poray M3\n");
printf("PQ3 - Poray Q3\n");
printf("PX5/6 - Poray X5/X6\n");
printf("PX8 - Poray X8\n");
printf("PR50 - Poray R50\n");
printf("MPR - MPR-L8 (HAME clone)");
exit(0);
}
checksum=0;
//Check device and choose encryption key
//M4 encrypt/decrypt not verified 0x32353335, so not presently included
if (!strcmp(device, "PM3")){
printf("Packing Poray M3 Image: ");
f.magic=0x31353335;
memcpy(mykey, PORkey, sizeof(PORkey));
checksum=-1; //HACK, I don't know why it needs this.
} else if (!strcmp(device, "PQ3")){
printf("Packing Poray Q3 Image: ");
f.magic= 0x33353335;
memcpy(mykey, PORkey, sizeof(PORkey));
} else if (!strcmp(device, "PX5/6")){
printf("Packing Poray X5/X6 Image: ");
f.magic=0x35353335;
memcpy(mykey, PORkey, sizeof(PORkey));
} else if (!strcmp(device, "PX8")){
printf("Packing Poray X8 Image: ");
f.magic=0x36353335;
memcpy(mykey, PORkey, sizeof(PORkey));
} else if (!strcmp(device, "PR50")){
f.magic=0x34353033;
memcpy(mykey, PO2key, sizeof(PO2key));
} else if (!strcmp(device, "MPR")){
printf("Packing MPR-L8 Image: ");
f.magic=0x32473352;
memcpy(mykey, MPRkey, sizeof(MPRkey));
checksum=-1; //HACK, I don't know why it needs this.
} else {
printf("I don't recognize the %s device, bailing out\n", device);
exit(1);
}
//Fill rest of header
f.imgflags = 0x020e0000;
f.junk[0]=f.junk[1]=f.junk[2]=f.junk[3]=0;
//Get files
//Open input and output files
infile = fopen(infname, "rb");
if (infile==NULL)
{
printf("Couldn't open input file\n");
exit(1);
}
outfile = fopen(outfname, "r");
if (outfile == NULL)
outfile = fopen(outfname, "wb");
else
{
printf("Output file already exists! \n-Quitting to avoid accidentally overwriting \n-your only copy of a firmware file.. :) \n");
fclose(outfile);
fclose(infile);
return(1);
}
if (outfile==NULL)
{
printf("Couldn't open output file\n");
fclose(infile);
exit(1);
}
//Read file to get data len
fseek(infile, 0, SEEK_END);
f.len=ftell(infile);
fseek(infile, 0, SEEK_SET);
data = (uint8_t*)malloc(f.len+2);
if(data==0)
{
printf("Couldn't allocate memory, bailing out\n");
exit(1);
}
printf("Reading %X bytes from input file\n", f.len);
//Get the data
fread(data, f.len, 1, infile);
//Look for right data
if (data[0]!=0x27 || data[1]!=0x05 || data[2]!=0x19 || data[3]!=0x56)
{
printf("Error - Input data doesn't look like a uImage (bad header). I can't continue for risk of brick..\n");
exit(1);
}
//DO CHECKSUM
printf("Checksum Calculation...\n");
for (i=0; i<f.len-1; i+=2)
{
//if ((i<8)||(i>f.len-8)) printf("---i=%x, tempH=%X, tempL=%X\n", i, data[i+1], data[i]); //debug see some data
checksum += (data[i+1] << 8 ) | data[i];
}
printf("i=%X, f.len=%X\n",i,f.len);
if (i < f.len)
{
checksum += data[i];
printf("Got odd byte: %X.\n", data[i]);
i+=1;
}
//printf("Generating checksum...\n");
//printf("Checksum1 = %X\n", checksum);
checksum = checksum + (checksum >> 16);
//printf("Checksum2 = %X\n", checksum);
checksum = 0xFFFF + checksum;
//printf("Checksum3 = %X\n", checksum);
checksum = ~(checksum + (checksum >> 16));
//printf("Checksum4 = %X\n", checksum);
checksum = checksum & 0xFFFF;
printf("Checksum = %X\n", checksum);
data[i] = checksum & 0xFF;
data[i+1] = (checksum >> 8) & 0xFF;
printf("File Checksum: %X, %X\n", data[i+1], data[i]);
printf("Encrypting %X bytes...\n", f.len+2);
//Encrypt
for (i=0; i<=f.len+2; i++)
{
data[i] = data[i] ^ mykey[i % 15];
}
//Write to the new file
printf("Writing header\n");
fwrite(&f, sizeof(f), 1, outfile);
printf("Writing %X bytes...\n", f.len);
fwrite(data, f.len+2, 1, outfile);
fclose(infile);
fclose(outfile);
free(data);
return 0;
}
(Last edited by oschemes on 10 Apr 2013, 04:05)