The firmware for the current generation Nikon DSLR camera’s have the firmware files packed into a single package, and this is then ‘encrypted’.
The package files is just XOR’ed with a three layer nested XOR pattern.
The first layer is a 256 byte pattern that is repeated across the file, then next over this there is a 256 byte pattern that is applied one byte at a time across each layer one pattern iteration. This is repeated again with another (layer three pattern) of 256 bytes that are applied, one byte at a time across the layer two pattern. Thus creating a one time pad that covers 2^24 bytes or 16MB. And what luck the largest firmware package Nikon has produced for the D3100 is 16MB.
So the code to un-XOR a file:
static void ExactFirmware4(string fileName)
{
if (File.Exists(fileName))
{
BinaryReader br = null;
BinaryWriter bw = null;
try
{
br = new BinaryReader(File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
bw = new BinaryWriter(File.Open(fileName + ".out.bin", FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
int count = (int)br.BaseStream.Length;
byte[] data = br.ReadBytes(count);
for (int i = 0; i < count; i++)
{
int ord1_idx = i & 0xFF;
int ord2_idx = (i >> 8) & 0xFF;
int ord3_idx = (i >> 16) & 0xFF;
int b = data[i] ^ Xor_Ord1[ord1_idx] ^ Xor_Ord2[ord2_idx];
int fix = Xor_Ord3_Eye[ord3_idx] ^ fixKnownTRUE[ord3_idx];
data[i] = (byte)(b ^ fix);
}
bw.Write(data);
}
finally
{
if (br != null)
br.Close();
if (bw != null)
bw.Close();
}
}
}
The code above refers to four Xor data sets. The first two Xor_Ord1 and Xor_Ord2 were found by just looking at the files. The fixKnownTRUE was found by searching all possible comibinations of XOR mask, and then search for text like ‘Nikon’ or other words observed in the older non-encrypted firmware files. Then the last set of data Xor_Ord3_Eye were found by looking at the transitions from block to block, and where one end with fifty 0xFF and the next had fifty 0xAD the next value was 0×52. That left a very few number of blocks that still were unknown, and for those I mainly used the difference in file alignment between the two D7000 firmware releases to see the same byte clean and encrypted.
So the actually useful stuff, the XOR data patterns:
static byte[] Xor_Ord1 = {
0xE8, 0xFE, 0x46, 0xE3, 0x7D, 0xAB, 0x5C, 0xB9, 0xA5, 0x53, 0xC4, 0xC7, 0x32, 0xCD, 0x9C, 0xED,
0x94, 0x67, 0x4E, 0x5B, 0x48, 0x3A, 0x52, 0xB6, 0x34, 0xF7, 0x8E, 0x12, 0x90, 0x98, 0x82, 0x3C,
0x09, 0x2B, 0x68, 0xA8, 0x24, 0xD5, 0x10, 0x9D, 0x9A, 0xD9, 0xA9, 0x7F, 0x50, 0x4B, 0xDD, 0x9E,
0x62, 0x1C, 0x6A, 0x64, 0x02, 0x11, 0xDA, 0x4A, 0x6E, 0x35, 0xBD, 0xA0, 0xB1, 0xD7, 0xDE, 0x83,
0x5D, 0xE5, 0x5E, 0xCC, 0xDB, 0xAC, 0x18, 0xE2, 0x25, 0x69, 0x07, 0xBC, 0x39, 0x97, 0x14, 0xEB,
0xB2, 0x73, 0x36, 0x8A, 0x99, 0xB8, 0x1E, 0x2E, 0xEF, 0x93, 0xBA, 0xEE, 0xF5, 0xC5, 0x7B, 0x74,
0x8D, 0xE1, 0xC3, 0x4F, 0x41, 0x42, 0x6C, 0xE6, 0xA2, 0x06, 0x6F, 0x85, 0x2A, 0x2F, 0x1B, 0x38,
0x08, 0xAF, 0x44, 0x00, 0x33, 0x63, 0x91, 0x22, 0x87, 0x70, 0xB0, 0x43, 0xB5, 0x66, 0xE0, 0xFF,
0x30, 0xAD, 0x8F, 0xC1, 0xF4, 0xEA, 0xF9, 0xF6, 0x51, 0xD6, 0xD4, 0x3E, 0x04, 0x72, 0x3D, 0x54,
0x78, 0xC0, 0x7E, 0x26, 0xFA, 0x56, 0x58, 0xC9, 0x55, 0xC8, 0xA6, 0x16, 0x23, 0x84, 0xB7, 0xCB,
0x45, 0x7C, 0xD8, 0x7A, 0x27, 0x2D, 0xCA, 0x03, 0x3F, 0x17, 0x0B, 0x57, 0xBB, 0x3B, 0xF0, 0x49,
0x1F, 0xD1, 0x86, 0x80, 0x95, 0x20, 0x6B, 0xC6, 0xBF, 0xAA, 0x79, 0xD2, 0x75, 0xCF, 0xAE, 0xD0,
0x5F, 0xF1, 0x61, 0xF3, 0xFB, 0xCE, 0x29, 0x65, 0x0F, 0x31, 0x2C, 0xFD, 0x76, 0x0C, 0x4C, 0x4D,
0x60, 0xF8, 0x88, 0x6D, 0xA4, 0xEC, 0x9B, 0x92, 0x47, 0xA1, 0xE4, 0x21, 0xFC, 0x81, 0xA7, 0xC2,
0x0E, 0xA3, 0x40, 0x0D, 0x8B, 0x59, 0x96, 0x37, 0xE7, 0xF2, 0x77, 0x1D, 0x28, 0x0A, 0x8C, 0x5A,
0x15, 0x9F, 0x01, 0xB3, 0xD3, 0xBE, 0xB4, 0x1A, 0x89, 0xE9, 0x13, 0x05, 0xDF, 0xDC, 0x71, 0x19,
};
static byte[] Xor_Ord2 = {
0x76, 0x0F, 0x43, 0xD9, 0xDB, 0xDC, 0x9B, 0x49, 0x4E, 0x42, 0xB7, 0x9F, 0xEC, 0x55, 0x19, 0x11,
0x58, 0x23, 0x69, 0xA2, 0xB8, 0x68, 0xE8, 0x2B, 0x91, 0xF3, 0x1A, 0x34, 0xED, 0x0A, 0x06, 0x89,
0xB2, 0x79, 0x2A, 0xC8, 0xEE, 0xA3, 0xB5, 0xD0, 0xFD, 0x17, 0xF9, 0xCE, 0x74, 0x39, 0x47, 0xC5,
0xC1, 0x5D, 0x86, 0x7F, 0x6A, 0xAB, 0xE5, 0xF5, 0xC9, 0x96, 0x71, 0x1C, 0x09, 0x25, 0xD3, 0x8C,
0x0C, 0x02, 0xB1, 0x48, 0x7C, 0x46, 0x3E, 0x08, 0x7B, 0x01, 0x54, 0x6B, 0xB9, 0x4F, 0xCD, 0xF1,
0x51, 0x50, 0x59, 0xA4, 0xA7, 0x6C, 0x3F, 0xB6, 0x9D, 0xBC, 0x4C, 0x9E, 0x16, 0x37, 0xA1, 0xC0,
0x6E, 0xE2, 0xDA, 0x3D, 0x22, 0xCB, 0xE7, 0x5B, 0x98, 0x53, 0x92, 0x36, 0x90, 0xAC, 0x31, 0x24,
0x21, 0xC6, 0x63, 0x35, 0xB4, 0x5C, 0x1F, 0x77, 0x4A, 0xE4, 0x0D, 0x13, 0x8D, 0xC7, 0x99, 0x7E,
0x81, 0x3C, 0x60, 0x28, 0xF0, 0xBF, 0x82, 0x2C, 0x78, 0x7A, 0x5F, 0x93, 0x84, 0x70, 0xEA, 0x9A,
0x8E, 0xD2, 0x27, 0xE0, 0xCF, 0x6D, 0x10, 0x9C, 0x56, 0x07, 0x12, 0xFA, 0x26, 0x97, 0x80, 0xE3,
0xE1, 0x61, 0x8A, 0x75, 0xA9, 0x5A, 0xDE, 0x1E, 0x5E, 0x4D, 0x66, 0x0E, 0xBA, 0x4B, 0x20, 0x40,
0xA8, 0x8F, 0x52, 0x7D, 0xDF, 0xE6, 0xAF, 0x6F, 0xBE, 0xFC, 0x94, 0xA0, 0x3A, 0x33, 0x45, 0x14,
0x62, 0x00, 0x87, 0xAE, 0xB3, 0x8B, 0xD4, 0xCA, 0xFF, 0xE9, 0x04, 0x88, 0xCC, 0x41, 0xD7, 0xD6,
0xBB, 0x95, 0x32, 0x18, 0xF8, 0x72, 0x65, 0x3B, 0x29, 0xAD, 0x44, 0x1B, 0xC2, 0xD8, 0x1D, 0xA5,
0xDD, 0x67, 0xD5, 0x30, 0xA6, 0xEF, 0x2F, 0xF2, 0x83, 0x2D, 0x03, 0xBD, 0x15, 0x2E, 0xD1, 0x73,
0x57, 0xAA, 0xFB, 0x85, 0xF4, 0x64, 0x0B, 0xC4, 0xF7, 0xEB, 0x38, 0xC3, 0xF6, 0x05, 0xFE, 0xB0,
};
static int[] Xor_Ord3_Eye = {
/*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/ /*a*/ /*b*/ /*c*/ /*d*/ /*e*/ /*f*/
/*00*/ 0x00, 0x25, 0x06, 0xbb, 0xe3, 0x82, 0x70, 0xce, 0x86, 0xfb, 0x100, 0x3a, 0xf8, 0xbf, 0x76, 0xf5, /*00*/ // 0x0a is 0x00, therefore put 0x100.
/*10*/ 0xc3, 0xf6, 0x9d, 0x9e, 0x10, 0x00, 0xfc, 0x9c, 0xdd, 0x12, 0x46, 0x93, 0x4f, 0xa6, 0xad, 0x68, /*10*/
/*20*/ 0x94, 0xb8, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, /*20*/
/*30*/ 0x3e, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xba, 0xb2, 0xd0, 0x79, 0xa5, 0x00, 0x00, 0x6a, 0x00, 0xd4, /*30*/
/*40*/ 0x83, 0x55, 0x87, 0x9b, 0x5c, 0x27, 0xab, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*40*/
/*50*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*50*/
/*60*/ 0x00, 0x00, 0xcb, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*60*/
/*70*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x37, 0x90, 0xe8, 0x3b, 0x92, /*70*/
/*80*/ 0x35, 0x4b, 0xd2, 0xd7, 0xd8, 0x0e, 0x51, 0x8b, 0xb0, 0xec, 0x4c, 0xb9, 0x59, 0x2e, 0x66, 0x54, /*80*/
/*90*/ 0xb5, 0xd1, 0x00, 0x1E, 0x0f, 0x5a, 0xc4, 0xcd, 0xeb, 0x4e, 0x7c, 0x74, 0x8e, 0xfa, 0x81, 0xe2, /*90*/
/*A0*/ 0x7f, 0x9a, 0xa8, 0x5f, 0x32, 0x89, 0x98, 0x07, 0x39, 0xc0, 0x38, 0x1f, 0x01, 0xe0, 0x8d, 0x1d, /*A0*/
/*B0*/ 0xf3, 0x96, 0x57, 0xa0, 0x0b, 0xed, 0x09, 0x18, 0x8c, 0xf4, 0x0d, 0x21, 0xd9, 0x23, 0x78, 0xa1, /*B0*/
/*C0*/ 0xc1, 0xfe, 0x3c, 0x30, 0x73, 0x5d, 0x40, 0x99, 0xb6, 0x6c, 0x7b, 0x14, 0xca, 0xc2, 0xe6, 0x8a, /*C0*/
/*D0*/ 0xe9, 0xae, 0x7a, 0xd6, 0xf1, 0x3d, 0xa4, 0x34, 0x2b, 0xda, 0x63, 0x84, 0xb3, 0xaf, 0x88, 0xb7, /*D0*/
/*E0*/ 0x45, 0x97, 0xdc, 0x20, 0x17, 0x3f, 0x4a, 0x52, 0x03, 0x33, 0xdf, 0xd3, 0x04, 0x69, 0x91, 0xf0, /*E0*/
/*F0*/ 0xf9, 0xcc, 0x50, 0x44, 0xff, 0x80, 0x58, 0xf7, 0xc9, 0x60, 0x6b, 0x53, 0xa7, 0x85, 0xee, 0x1c, /*F0*/
};
static byte[] fixKnownTRUE = {
/*00*/ 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*00*/
/*10*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*10*/
/*20*/ 0x00, 0x00, 0x00, 0xe1, 0x62, 0x5b, 0xcf, 0x67, 0x00, 0xe7, 0x48, 0x0c, 0x7e, 0x7d, 0xb1, 0x00, /*20*/
/*30*/ 0x00, 0x1b, 0xc5, 0x0a, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0xc6, 0x00, 0xa3, 0x00, /*30*/
/*40*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x42, 0x61, 0x2d, 0xb4, 0x4d, 0x1a, 0x9f, /*40*/
/*50*/ 0x64, 0x8f, 0xd5, 0x43, 0x05, 0x24, 0x72, 0x02, 0x41, 0x15, 0x6d, 0x6e, 0x47, 0x26, 0x65, 0x13, /*50*/
/*60*/ 0x49, 0x95, 0x00, 0x00, 0xef, 0x6f, 0x2c, 0xbd, 0xfd, 0xac, 0x31, 0xde, 0x2a, 0x5e, 0x29, 0xa2, /*60*/
/*70*/ 0xbc, 0x28, 0xc7, 0x56, 0xc8, 0x16, 0x75, 0xe4, 0x19, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*70*/
/*80*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*80*/
/*90*/ 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*90*/
/*A0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*A0*/
/*B0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*B0*/
/*C0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*C0*/
/*D0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*D0*/
/*E0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*E0*/
/*F0*/ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*F0*/
};
This was a very satisfying puzzle/project. Finding the layers of XOR was like parse the parcel as each layer was found.
I’ve read a lot of forum threads about people wanting the verious versions of the Nikon firmware hacked, it’s not happened so far, so I’m not to concerned what I’ve done, has distroyed value for Nikon.
So while it could be fun to sit down and try reverse engineer the code, I think I’m more interested using my camera to take photo’s.
[Updated: 26th Nov] fixed x93, x94, x95 in Xor_Ord3_Eye as these were missed
Damn, I would prefer that you hacked the firmware and then use the camera! :)
I wonder if this will information will bring any new help to the table. Thanks for posting!!
It might bring some action. Could be neat.
The only sensible thing that I would like is the ability to stop the single spot AF point moving when the arrow keys are bumped.
Hi Simeon, FYI
We have been chatting about it here: http://www.dvxuser.com/V6/showthread.php?266826-How-do-you-increase-Nikon-s-bit-rate-of-20-Mbps
Also Vitaliy (did the GH13 Hack) posted about it here:
http://www.personal-view.com/talks/discussion/1494/nikon-firmware-seems-to-be-decrypted
The ball is rolling, great work!!!
It’d be great to be able to get the FN button to control ISO in the viewfinder.
+1 for this!
Better control on auto ISO would also be very welcome… i.e. set the shutter speed as max(X, 1/(Focal Length * Y)), where X and Y are user configurable. You could set X to the lowest you ever want to shoot (say 1/30s), and Y to a multiplier for the hand-holding rule of thumb (i.e., 2 would result in a speed of 1/210 for a 105mm lens and 1/100 for a 50mm lens; 0.75 would result in 1/80s and 1/40s respectively).
I am dying for manual white balance in kelvin units. The d7k has this feature, I sure wish the d5100 had them. Oh that and manual control for video!
You can’t imagine how many people wait for you do that “fun” job
Pingback: Nikon firmware decrypted | Nikon Rumors
This is an interesting development. We use a D7000 but not as much as the Panny GH2s. If the hack gets developed within ptools or something, could be well interested in supporting it with test patches.
[comment complete rewriten to remove original contents but it was something like...]
Comment referring to Hex-Rays.IDA.Pro.Advanced downloadable via a torrent site.
There’s a difference in my mind between altering the firmware on your camera, and using copies of commercial software. This is not taking value out of Nikon’s pocket, where-as the later is taking from Hex-Rays.
It’s not actually a one-time pad, since in a one-time pad all the encoding symbols are independant of each other. It has some resemblance to the rotor systems used in World War II (German Enigma, US Sigaba, British Typex, Japanese Purple etc) but is less sophisticated as each of the component operations is a linear addition (mod 2), rather than the general substitution implemented by wired rotors. Anyway, well done in deciphering it.
Well if your the same Andrew Roos that wrote the weakness of RC4 paper, I’ll give your statements much weight, in regards to the not a one-time-pad nature of the XOR stream.
Yip, that’s me. Well done to you.
A fairly clean known cypher text attack, without reverse engineering what the hardware actually does. Very nice!
Pingback: Nikon DSLR Firmware Encryption Cracked, Let the Hacks Begin! | NikonHQ
It will be great to see also a hack wich allow manual controls on video on the D5100 !
If one could add sound level monitor and exposure levels monitor like in canon 5d mk2 it would be great. please please do something about it !!!!!!!!
Hello Simon.
is it possible to fix / set manual exposure in video mode for Nikon D5100 ?
As I say at work, “anything is possible with software… maybe just not feasible in the time frame your thinking….” honestly I can’t predict how long it will take to understand the firmware enough to identify the applicable things to change, or if things can be changed to how they are wanted, or who is interested in that part. As noted elsewhere, I brought my D5100 for pictures and I am not interested in video.
Is there news about the firmware ?
No news, I’m on work travel presently, and then on personal travel after that, for next 3+ weeks. I then have more work travel, so I’m not expecting much time in next 3-5 weeks.
Do you think a hack for the Nikon d40 would be possible?
Yes, it’s as equally possible as the D5100, as it use the same processor, and the base OS is the same.
Common, man!
Give us 720 60fps in d5100 :))
What would be. Realistic timescale for a new update for a d40?
Currently, never, based on nobody is working on it, and it’s not an active target for those doing work.
But when we understand the general firmware layout “flow” and there is a “do-able” alteration for D40, then I could imagine someone doing it.