Daniel's Blog

Posting random crap since 2017

Fooling Around With Fujifilm Firmware

Jul 30 2021 There's no need to write some kind of introduction to cameras here, so I'll get straight to the point. I recently got my hands on a cheap Fujifilm HS20 EXR. It's a pretty old camera (2012), but I thought it'd be a good way to practice my firmware hacking skills. The first thing I did was update to the latest firmware. It's pretty simple: just hold down the back button while powering up, and the rest is pretty straightforward. After the update, the camera wouldn't let me upgrade to the same version again. With that, I decided to dig into the firmware file contents. In a hex editor, the file doesn't look very interesting. No strings, and a weird looking header. Given that Fujifilm has made tons of different cameras, I decided to download as many different firmware files as I could and study them. This is what I came up with: Size in bytes Description 4 Hardware or OS version 512 Model information (?) (consistent on firmware updates for same model) 8 Firmware version 4 Checksum (different on all firmwares) 4 Checked several firmwares, generally just "1". to EOF Payload (bit flipped) It appears that Fujifilm has been using the same firmware format since ~2005, and continue to use it on their latest cameras. I noticed another different Fujifilm camera, the S-series, has another firmware format. These cameras have already been hacked by CHDK developers. It has easy-to-access secret menus and built-in scripting. Sadly, I didn't have this type of camera, and I would be on my own this time.

Creating a new firmware

Given that I bought this camera specifically for hacking, I knew I had to try and increment the firmware version by 1 and see if the camera accepted it. It seems risky, but I was willing to do it since I bought the camera specifically for hacking. Before I did that, I needed to do some testing. It appeared that the firmware version is printed in hex. Yep, that means when you download firmware version number "1.22", you are getting 1.32 in base 10. I confirmed this with a simple "1337" test: 1337 After fully understanding how this worked, I changed the firmware version from 1.4 to 1.5 and tried it. Amazingly, it installed perfectly. And a bonus: it doesn't increment the system's firmware version counter. Now, all I need to do is figure out the firmware payload. binvis.io It doesn't look encrypted or compressed, so this one should be relatively easy to solve. The people at CHDK have already gotten this far: the firmware is XORed with 0xff. All I had to do was go write a program to go through the file invert all the bits. Easy. I was quickly able to get it disassembled in Ghidra, all the data references pointed to an empty area in the firmware file (a bunch of 0xff). Although the code was basically unreadable, the strings in the firmware were very interesting. It mentions SQLite, "AUTO_ACT.SCR" (automatically activated script?), and possibly a hidden menu. After that, I decided to try and make my own firmware. The checksum looking number in the header scared me. Was it CRC32? Or was it some proprietary algorithm? How would I recreate it? After a few risky firmware update tests, it turns out it is just a simple case of "add up all the bytes and make sure it equals X." I had confirmed this by reversing a word in the firmware. backwards In order to inject my own custom text, all I had to do was subtract the checksum of both files and then change the header checksum accordingly. hacked by dan

Getting the Correct Disassembly

Completely hacked right? Well, custom code injection would be nice. Since the strings won't reference correctly to the code, I had no idea where would be a good place to inject my code. Then, I remembered the SQLite strings in the firmware. Since SQLite is open-source, I could match up some of the source and my decompiled code, and calculate the offset of the string references. After a while of Ghidra analysis, I noticed that some large numbers are sometimes stored under the function, along with addresses. I downloaded a 2010 revision of SQLite source code and searched for "0x". Of course, I needed to find a number that was unique, but I also needed a string referenced near it. The first thing I found was sqlite3Realloc(). I was quickly able to find it since it included 0x7fffff00 in the function. Sadly, no string was referenced here, so I kept digging. After finding allocateIndexInfo(), I was able to find several other allocation functions around it, such as sqlite3DbMallocZero(). The reason I mention that function is because in allocateIndexInfo(), it contains a call to sqlite3DbMallocZero() and a reference to the string "out of memory". Now, all I had to do was look at references to sqlite3DbMallocZero() and find a call that looked like this: pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(\*pIdxInfo) + (sizeof(\pIdxCons) + sizeof(\*pUsage))\nTerm + sizeof(\pIdxOrderBy)\*nOrderBy + sizeof(\pHidden) ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; } Eventually, I found something in the Ghidra decompiler that looked like a worthy canidate: FUN_0047e7e8(\param_1, iVar32 \* 0x14 + 0x2c + iVar20 \ 8); After a bit of looking around, everything seemed to match up. Now that I had the correct offset, I wrote a program to copy the strings over, and Voila! Readable code.

Code Injection

Now, that I had the strings correctly referenced, I needed to pick a place to inject my code. My first idea was to hijack the image saving process. I opened up a JPEG image, and looked around for some interesting things I could possibly hijack. The first thing I saw was "PrintIM". I searched it in my disassembly, and went to its reference to one function. After changing a few values and testing the resulting firmware file, I was confident this was a safe place to test my code. And indeed, it was. Whenever I took a picture, I could run my own custom assembly and output 29 bytes of whatever I want. Here's a screenshot where I tested how many bytes I could output: hack

A Conclusion

So what's next? Of course, writing custom firmwares to ROM is very dangerous, especially with the risky version update hack. The only reason I did it was because I bought the camera purely for hacking purposes. In order to tweak and add useful modifications to the camera, it should be done in a non-permanent way, such as via a special USB/PTP command, or uncovering anything else that could possibly allow code execution. And as always, the source code is completely open-source: https://github.com/petabyt/fujifilm Back