Nikon Firmware Insights #01

Here’s the first post in my Nikon Firmware investigations.

Firstly after removing the encryption from the Nikon DSLR firmware bundle file, we should extract each file from the bundle.

Form my looking at the files I have, there is 0x20 bytes of fluff, then there is a file count, header length, and a couple of dummy int32’s. Then there’s 0x10 bytes of file name, file start, length, and two more dummy int32’s. After that there’s a word ‘checksum’ and some padding bytes.

Thus this code (C#) pulls the files out of the bundle file decoded by the previous post:

static void ExactFirmware3(string fileName)
{
    if (File.Exists(fileName))
    {
        BinaryReader br = null;

        try
        {
            br = new BinaryReader(File.Open(fileName + ".out.bin",
                FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
            br.BaseStream.Seek(0x20, SeekOrigin.Begin);

            uint count = ReadUint32(br);
            uint headerlen = ReadUint32(br);
            uint dummy1 = ReadUint32(br);
            uint dummy2 = ReadUint32(br);

            var header = new List<Tuple<string,uint,uint>>();

            // Read Header
            for (int c = 0; c < count; c++)
            {
                string firmwareName = Path.Combine( Path.GetDirectoryName(fileName),
                    ReadString(br, 16));
                uint start = ReadUint32(br);
                uint len = ReadUint32(br);
                uint hdummy1 = ReadUint32(br);
                uint hdummy2 = ReadUint32(br);

                header.Add(new Tuple<string, uint, uint>(firmwareName, start, len));
            }

            foreach (var t in header)
            {
                DumpFile(br, t.Item1, t.Item2, t.Item3);
            }
        }
        finally
        {
            if (br != null)
                br.Close();
        }
    }
}

static void DumpFile(BinaryReader br, string fileName, uint start, uint len)
{
    BinaryWriter bw = null;

    try
    {
        bw = new BinaryWriter(File.Open(fileName, FileMode.Create, FileAccess.Write,
            FileShare.ReadWrite));

        br.BaseStream.Seek(start, SeekOrigin.Begin);

        var data = br.ReadBytes((int)len);

        bw.Write(data);
    }
    finally
    {
        if (bw != null)
            bw.Close();
    }
}

Now for the D5100 we have two files, a640m010100.bin and b640101b.bin. The D7000 firmware is x75xxxx.BIN, the D3100 is x74xxxx.BIN, D300S is x81xxx.BIN and the D3S is xD3Sxxx.BIN.

All these systems are running the ‘Softune REALOS/FR is Realtime OS for FR Framily’, the Axxxx.BIN firmware is for the IO control CPU (metering, focus, buttons) and the larger Bxxxxx.BIN is the main processor firmware, with the main UI and processing (Fujitsu FR CPU).

Some great insight was found from the D70 Hack Project, which was the only remaining information I found. It’s in German, so thank you Google Translate. Also D7000 tear by by Chipworks was very inspiring.

 

Interested in more, come join the us at Nikon Hacker, or use the Online Patch Tool (Help)

20 thoughts on “Nikon Firmware Insights #01”

  1. As noted this is how the D3S, D300S, D3100, D5100, D7000 firmwares are bundled.

    The D700 uses are different format, that’s not encrypted, but the bundle file is packed differently.

  2. Ahh, so your method requires two separately encrypted files with the same key… gotcha. I guess it wouldn’t hurt trying to decrypt the 1.00 d90 firmware with this keys for grins.

  3. Well 80% of the decoding was done just from looking at a single D7000 firmware, but it was simpler in the end to using the many firmware files comparatively, to is the differences in alignment due to changes, to find common stuff at decoding boundaries.

  4. Small question, Simeon : I don’t understand the end of your sentence “After that there’s a word ‘checksum’ and some padding bytes.” in your post above.
    If I’m not mistaken, the header length is split into :
    – 0x20 fixed bytes (no idea what they mean, but they are constant across all models and versions),
    – then 0x10 bytes (4 int32s, that is, as you describe : number of files, header size, 0, 0)
    – then, for each file, a record of 0x20 bytes.
    So we have 0x20+0x10+2*0x20=0x70 bytes for the header, and then actual data begins, so there is no space left for a checksum or padding bytes…
    Is there something I’m missing ?

  5. The package has three parts. The header. The contents. The footer. The footer has the checksum and padding. BUT the package checksum is not checked.

    Each firmware file (referred to as A & B) has a checksum as the last two bytes of the file. Those are the checked checksums.

  6. $ python nikon_fir_dump.py D7000_0103_ext.bin

    --- header ---
    0x0000: ? = 91873f9a04d225c0dc2abdbe4bb4e594ed1e372231432bcf4d8ef76be9e1fb45
    0x0020: nb_record = 2
    0x0024: 1st record offset = 0x70
    0x0030: ---  record name  |  offset  | length ---
      0x0030: a750010202.bin   0x00000070 0x000c0002 0 0
      0x0050: b750103a.bin     0x000c0072 0x00840000 0 0
    --- contents ---
      0x00000070:  3c1abfc0275a05000340000800000000 ...
                   ... ffffffffffff0102020011032418493a , length = 0xc0002
      0x000c0072:  9f8050000000c011150187109f8f6800 ...
                   ... ffffffffffffffffffffffffffff40c0 , length = 0x840000
    --- footer ---
    0x00900072:  608f0000000000000000000000000000
    
  7. Oh, I see, you were talking about the end of the file while I was thinking “end of the header”. Thanks for clarifying.

  8. hi Simeon,

    Thanks for the beautification. I still miss 2 things: I tried yesterday to compute the CRC for the package, using the same algorithm from offset 0x70 to offset of Footer (just before the chechsum). But it does not work. And why the CRC for firmware B of D5100 is wrong althougt it is OK for D7000 one ? You are producing 100% correct firmware (like us on Canon firmware, which uses AES 128 ;-) for your D5100, so you should have understood this point…
    FYI, for Canon, package signatures (roughly HMAC-SHA1) were not checked… until 7D. They are now required.
    Here are my results on D7000 and D5100

    $ python nikon_fir_dump.py -c D7000_0103_ext.bin
    Dump decrypted Nikon firmwares v0.2
    based on work by http://simeonpilgrim.com
    
    --- header ---
    0x0000: ? = 91873f9a04d225c0dc2abdbe4bb4e594ed1e372231432bcf4d8ef76be9e1fb45
    0x0020: nb_record = 2
    0x0024: 1st record offset = 0x70
    0x0030: ---  record name  |  offset  | length ---
      0x0030: a750010202.bin   0x00000070 0x000c0002 0 0
      0x0050: b750103a.bin     0x000c0072 0x00840000 0 0
    --- contents ---
      0x00000070:  3c1abfc0275a05000340000800000000 ...
                   ... ffffffffffff0102020011032418 493a , length = 0xc0002, sum = 0x493a
      0x000c0072:  9f8050000000c011150187109f8f6800 ...
                   ... ffffffffffffffffffffffffffff 40c0 , length = 0x840000, sum = 0x40c0
    --- footer ---
    0x00900072:  608f 0000000000000000000000000000
    package sum=0x0
    

    and

    $ python nikon_fir_dump.py -c ../d5100/D5100_0101_ext.bin
    Dump decrypted Nikon firmwares v0.2
    based on work by http://simeonpilgrim.com
    
    --- header ---
    0x0000: ? = 91873f9a04d225c0dc2abdbe4bb4e594ed1e372231432bcf4d8ef76be9e1fb45
    0x0020: nb_record = 2
    0x0024: 1st record offset = 0x70
    0x0030: ---  record name  |  offset  | length ---
      0x0030: a640m010100.bin  0x00000070 0x000c0002 0 0
      0x0050: b640101b.bin     0x000c0072 0x00a80000 0 0
    --- contents ---
      0x00000070:  3c1abfc0275a05000340000800000000 ...
                   ... ffffffffffff0101000011101116 a1c6 , length = 0xc0002, sum = 0xa1c6
      0x000c0072:  9f8050000000c01115019b0003e09f81 ...
                   ... ffffffffffffffffffffffffffff 7c09 , length = 0xa80000, sum = 0x30f2
    --- footer ---
    0x00b40072:  8a47 0000000000000000000000000000
    package sum=0x16d5
    

    I’ll publish my script when bugs will be fixed…

  9. Your correct the 3rd order XOR table had three missing values, once there were set correct the D5100 & D3100 checksums are 100% same setup as D7000.

    My bad.

  10. OK. This time it’s for good : I think I have the params for the “bundle” checksum, and I think it is mandatory to compute it.
    As I don’t want to spam Simeon’s blog more than it is already, I joined Max’s brand new nikonhacker forum and posted my thoughts here :
    http://nikonhacker.com/viewtopic.php?f=2&t=8
    Any comment is welcome – but on that thread please ;-)

Comments are closed.