Novatek (NT9665X) firmware studies

Last edited:
Close his eyes, and hear the sound of distant axes chopping trees :)
 

Attachments

  • EasyUSB Writer.zip
    962.9 KB · Views: 62
looks like Nucklear gave up too. That is the method to decompress the image though. might be good to see how this problem is solved by the gopro people on their similar chipsets.

usb tools. https://github.com/evilwombat/gopro-usb-tools

some gopro and this novatek both use RTOS
 
Last edited:
There is a nice opportunity to find out the checksum calculation algorithm used in Novatek cams. Here are two unpacked NT96550 firmware files. They differ only with checksum bytes:
View attachment 25679
and bitrate setting bytes:
View attachment 25680

https://drive.google.com/file/d/0B4tyaJWIqCb_YnZISzlqQTV3M2s/view?usp=sharing
This comparison is almost perfect. Just need one more sample I guess.. So if anyone knows about a Novatek firmware with different bitrates, please inform me.
What I've researched so far regarding the checksum:
(definition even/odd bytes: even bytes: byte 0, 2, 4, 6, ... odd bytes: byte 1, byte 3, byte 5, ....)

  • checksum seems to be a WORD, the high bytes of the checksum DWORD remain constant over different firmwares from different models (0x55, 0xaa) - assuming big endian for checksum
  • the checksum function seems to be rather easy/linear. Unlike CRC sum which completely changes if only a bit is swapped, the checksum from novatek remains the same if for example only even bytes are modified. Hard to explain, see this example:
Code:
AA BB CC DD  <- checksum for these bytes = X  -> AA + CC = 176; BB + DD = 198
checksum does not differ for these examples:
AB BB CB DD (sum of even bytes  and odd ones remains the same) => AB + CB = 176, BB + DD = 198
CC BB AA DD(sum of even bytes  and odd ones remains the same) => CC + AA = 176, BB + DD = 198
....

checksum does differ for these examples:
AA BB CC DE (sum + 1) => AA + CC = 176; BB + DE = 199 <- error
AB BA CC DE (sum of even bytes changed as well as the sum of the odd ones) => AB + CC = 177 <- error; CC + DE = 1AA <- error
  • it probably uses two multipliers, one for even bytes, another one for odd bytes. to calculate this, i need more examples. i am not a math pro unfortunately...
If I did not completely forget my math knowledge, this should apply to the screenshot on top of page 2:
0x40*x1 + 0x1F*x0 = y
0x10*x1 + 0x27*x0 = y - 0x7D0
 
Last edited:
More research based on another compareable firmware sample (thanks @kotysoft ):
I guess I'm about to crack the algorithm, just need to do the math now for these findings:
Assumption: Unlike the rest of the firmware, the checksum has big endian byte sex

Code:
===============================================
nanoQ firmware with different bitrates:

old checksum:
0xcb8b = 52107
mod:
E:.
O:0x40 -> 0x10 -- -0x30
E:0x1f -> 0x27 -- +0x08
O:.
new checksum:
0xc3bb = 50107

diff to old: -0x2000


===============================================
nanoQ firmware with different metering tables:

old checksum:
0xcb23 = 52003
mod:
E:0x12 -> 0x52 -- +0x40
O:.
E:0x40 -> 0x43 -- +0x03
O:.
new checksum:
0x8823 = 34851

diff to old: -0x4300

The second sample only modified even bytes, so only one multiplicator is used: with 0x40 diff and 0x03 diff and a result of -0x4300 diff it looks like "-0x100"

EDIT: multiplicator for odd bytes seems to be 0x200. It would work with the above examples, but that would create a new issue: The lower bytes would always be zero. Maybe they are dropped?

EDIT2: New assumption: checksum isnt treated as big endian - it consists of two sums: 1 byte even checksum and 1 byte odd checksum.


EDIT3: I semi-cracked the algorithm now. I can update the checksum for modified even bytes, just need to find out, how the odd bytes are calculated. Btw: Checksum is 16bit little endian

EDIT4: its cracked. just need to fancy it up a bit and have to find out more about the initial value
This is a mainly for updating an existing binary:
Code:
        //algorithm: short chksm; little endian
        //        init: chksm=?;
        //        for every byte in firmware binary except checksum address at 0x6c,0x6d,0x6e,0x6f
        //            evenb: chksm-=<BYTE>
        //            oddb:  chksm-=<BYTE>*0x100
        //        done
 
Last edited:
...
EDIT3: I semi-cracked the algorithm now. I can update the checksum for modified even bytes, just need to find out, how the odd bytes are calculated. Btw: Checksum is 8byte little endian

EDIT4: its cracked. just need to fancy it up a bit and have to find out more about the initial value
Code:
        //algorithm: short chksm; little endian
        //        init: chksm=?;
        //        for every byte in firmware binary except checksum address at 0x6c,0x6d,0x6e,0x6f
        //            evenb: chksm-=<BYTE>
        //            oddb:  chksm-=<BYTE>*0x100
        //        done

Wow! Thank You so much, you're awesome!
I can't wait for firmware tools coming next based on this :)

What do you think, it should work with all NT96655 daschams?
 
Wow! Thank You so much, you're awesome!
I can't wait for firmware tools coming next based on this :)

What do you think, it should work with all NT96655 daschams?
Yes I think so. Will try to find out more about the initial value, for nanoQ it seems to be ffff ff85 but im struggling with other models. It should be a constant but it differs for other firmwares. Maybe my math is wrong somewhere, needs more evaluation first
 
EDIT: might still be correct, but i just realized, that i used a compressed sample firmware to evaluate the results. Please wait for more information. I used a partially compressed firmware from SG to test it - but I am not sure if it gets uncompressed before the checksum is calculated. The nano firmwares are completely compressed, so they need to be unpacked before calulation

I was able to recreate the checksum algorithm in c:
Code:
uint16_t calc_checksum(uint16_t data[], uint32_t length) {
    uint32_t pos = 0;
    uint16_t checksum = 0;
    while(pos < length) {
        checksum += pos + data[pos];
        pos++;
    }
    return checksum;
}

BUT: There is one problem with the algorithm: It's off by a constant - well not really a constant.
This constant depends on the model/maybe chipset.
Example:
For StreetGuardian the "key" is 0x10000. I checked it for many SG9665GC firmwares
For nanoQ 0903 the "key" is 0x17BB4. Also works for various 0903 firmwares.

I couldnt find the "key" inside the firmware binary, so probably the bootloader knows it. Maybe it's some kind of identifier to make sure you cant crossflash firmwares from different models. Or it depends on the hardware. chipset x1 has key1, chipset x2 has key2, ...

TLDR: To get the correct checksum, first calculate the checksum with the algorithm above and then subtract it from the "key". (real_checksum = (KEY-calc_checksum(...))&0xFFFF)
Possibly I just made things more complicated than they are, if you have any suggestions or improvements, let me know!

The attached file calculates the checksum for you. usage: ntk_chksm.exe firmware.bin
 

Attachments

  • ntk_chksm.zip
    4.9 KB · Views: 26
Last edited:
I'm not sure about the key, but NT96660 loader looks for WRKEY.BIN file on start.
 
I'm not sure about the key, but NT96660 loader looks for WRKEY.BIN file on start.
How do you know that? Are there any loader binaries around?

"Unfortunately" I'm away for the next few days, so happy new year all :D
 
Little update on the algorithm:
It's returns the correct checksum for SG and GITUP firmwares without a "key" value. It doesnt work for nanoQ, since it seems to use a different starting/base(?) value. Looking into this right now.
Code:
uint16_t calc_checksum(uint16_t data[], uint32_t length) {
    //algorithm expects that the WORD at 0x6e (checksum address) is 0x0000, otherwise it wont work correctly.
    uint32_t pos = 0;
    uint16_t checksum = 0;
    while(pos < length) {
        checksum += pos + data[pos];
        pos++;
    } 
    //added twos complement which was obvious due to >> 0x10000 - (previous checksum algorithm result) = real checksum <<
    return (~checksum & 0xFFFF) + 1;
}

Unbenannt.png
 
DSC_2636.JPG

So whats next: The firmware knows if its raw, partly-compressed or fully compressed. (fully compressed is probably detected by magic constant BCL1)
raw: 0x78 = 0x00000001
compressed: 0x78 = 0x00000000

Some firmwares contain multiple LZ77 compressed images (gitup2) some not. What does the second image do? (Maybe something eCos related)

And soon I'll release a tool that calculates the start value for non-standard checksum calculation.
Checksum calculation tool is already live, see attachment
 

Attachments

  • checksum.zip
    20.5 KB · Views: 14
Unpacked BCL1 partition from loader.

What does the second image do? (Maybe something eCos related)
I believe the second image is called 'IQ'
 

Attachments

  • ld-unp.zip
    11.5 KB · Views: 17
Last edited:
Ok now I'm wondering how small the flash memory is. I unpacked a firmware binary, updated its checksum and tried to flash the unpacked firmware.. this is the result:
Code:
NPT
Loader B40SB Start ...

655B_DDR3_LV1_3_2048Mb 09/26/2015 09:27:27

R[....many 'R' chars...]RRRNonComp

Ud FW
!!FW CODE SIZE > FLASH SIZE!!

The unpacked firmware size is 4,49MB - the original filesize was 2,45MB

Edit: NonComp = Not compressed/partially compressed
FullComp = fully compressed
 
Last edited:
Little update:
To successfully modify firmware binaries we still need to:
  • reverse/fix bfc compression, since it is a bit different to the publicly available bcl: http://bcl.comli.eu/
  • FullComp firmwares: the BCL header is slightly different: standard header: 0x42434c31 0x00000009 <-> novatek bcl header: 0x42434c31 0xYYYY0009 (where YYYY is a WORD based on the binary)
  • NonComp firmwares: They are all partially compressed from what I've seen. Even some FullComp firmwares contain another partially compressed area at 0x000b0000 (this bfc compressed blob does not contain the YYYY word)
YYYY word research:
  • First guess: It might be another checksum
Tried to evaluate that with 0903 firmwares that differ only in 3 bytes (excluding YYYY word):
Code:
endianess: little endian
center.bin:
cksm@0x4: bd0c
0x000046: 23cb
0x12b8e4: 1238
0x12bf8c: ac40

multi.bin:
cksm@0x4: 7d4c     (diff:-3FC0)
0x000046: 2388     (diff:-0043)
0x12b8e4: 5238     (diff:+4000)
0x12bf8c: ac43     (diff:+0003)

sum diff: 0x00
I wont say I proved it, but it really seems to be a checksum again. Time to crack another checksum? Hopefully it's the same algorithm as the novatek firmware checksum algorithm. (I think so)
Needs more investigation, unfortunately I don't have too much sparetime atm
 
Back
Top