Kindle 3.1 Jailbreak

I was bored one weekend and decided to jailbreak the new Kindle firmware. It was time consuming to find bugs, but not difficult. Unlike the iPhone, the Kindle doesn’t really have security. They have a verified FS and signed updates and that’s it, but I will still call my jailbreak an “exploit” just to piss you off. Previous Kindle 3 jailbreaks worked (AFAIK, I haven’t really looked into it) by tricking the Kindle into running a custom script by redirecting a signed script using a syslink. This worked because the updater scans only “files” that do not end with “.sig” (signature files to validate the file). They fixed this now by scanning all non-directorys that do no end with “.sig”. This is the first bug I’ve exploited. Part one is getting the files into the update, which I did by conventionally renaming them to “.sig” even though they’re not signature files. Part two is harder, getting the unsigned script to run.

How the Kindle updater works is that first it gets a list of all files (including files in subfolders, excluding signature files) in the update and checks it’s signature with Amazon’s public keys. If you modify any of the scripts from a previous update, the signature is broken and the Kindle won’t run it. If you add your own scripts, you can’t sign it because you don’t have Amazon’s keys, and finding them would take more then the lifespan of the universe. (SHA256 HMAC). They also use OpenSSL to check the signatures, so trying to buffer overflow or something is out of question (or is it? I haven’t looked into it). Afterwards, when all files are matched with their signatures and checked, the updater reads a “.dat” file which contains a list of all scripts, their MD5 hash and size (to verify, I don’t see the point since they were just signature checked. Maybe a sanity check?). It finds the “.dat” file using “find update*.dat | xargs” which means all the .dat file has to be is start with update and end with .dat. They don’t care what is in between. Next, they read the file using “cat” and with each entry, verify the hash and loads the script. Well, conventionally, “cat” can read multiple files if more then one filename is given in the input. This means if the update*.dat file contains spaces, then “cat” will read every “filename” separated by a space. I took a signed .dat from one of Amazon’s update. Renamed it “update loader.sig .dat” and placed my actual .dat (containing an entry to the script jailbreak.sig, a shell script renamed) in loader.sig. jailbreak.sig untars payload.sig, a renamed tgz file which contains the new keys we want to use to allow custom updates. Amazon’s updater only signature checks “update loader.sig .dat” which is valid. Then cat tries to read the files “update”, “loader.sig”, and “.dat”, one of which exists and the others silently fail. Loader.sig points to the script jailbreak.sig which the updater happily loads thinking it’s already signature checked. Jailbreak.sig, calls tar to extract payload.sig and copies the new keys to /etc/uks and installs a init.d script to allow reverting to Amazon’s keys for installing future updates. Now we own the system again!

tl;dr:

A download to the jailbreak can be found here. Directions are provided in the readme file. Use it at your own risk (I’m not responsible if you somehow brick it) and note that it most likely will void your warranty. Make sure to uninstall all custom updates before you uninstall the jailbreak, as after uninstalling the jailbreak, you cannot run custom packages until you jailbreak again. Directions for switching between custom updates and Amazon updates can be found in the readme file.

Compiling the Linux kernel for Amazon Kindle

So, I recently bought a Kindle 2. As usual, the minute it arrived, I ripped it apart, poked every chip, and then started to reverse engineer the damn thing. Wait. I didn’t have to! I found this out days late, after messing with IDA Pro. Amazon has generously released most of the back end code for the Kindle as open source. (The front end, aka the stuff you see, is written in Java and we might get to that another day). So I decided to compile my own Kindle kernel. Why? Why not. Here’s how:

Part 1: Prerequisites

  • Get a root shell of your Kindle. If you don’t know, Google “usbNetworking”
  • A Linux computer for compiling code
  • Amazon’s sources for your version of the Kindle: http://www.amazon.com/gp/help/customer/display.html?nodeId=200203720
  • An ARM cross-compiler. You can compile Amazon’s code, or if you’re lazy, use CodeSourcery’s precompiled toolchain: http://www.codesourcery.com/sgpp/lite/arm
  • The following packages, get them from your distro’s repo: libncurses-dev (for menuconfig), uboot-mkimage (for making the kernel image), and module-init-tools (depmod)

Part 2: Compiling the kernel

  1. Extract the source to anywhere. If you can’t decide, use “~/src/kernel/” and “cd” to the source files.
  2. Now, you need to configure for the Kindle, type “make mario_mx_defconfig
  3. Edit the “.config” file and look for the line that starts with “CONFIG_INITRAMFS_SOURCE“. We don’t need that, delete that line or comment (#) it out.
  4. Here’s the part were you make all your modifications to the kernel. You might want to do “make menuconfig” and add extra drivers/modules. I’ll wait while you do that.
  5. Back? Let’s do the actual compiling. Type the following: “make ARCH=arm CROSS_COMPILE=~/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- uImage”. This will make the kernel image. I assume you installed CodeSourcery’s cross compiler to your home folder (default). If your cross compiler is elsewhere, change the command to match it.
  6. Compile the modules into a compressed TAR archive (for easy moving to the kindle): “make ARCH=arm CROSS_COMPILE=~/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- targz-pkg” (again, if your cross compiler is installed to a different location, change it).
  7. For some reason, depmod refuses to run with the compile script, so we’re going to do it manually. Do the following “depmod -ae -F System.map -b tar-install -r 2.6.22.19-lab126 -n > modules.dep” Change 2.6.22.19-lab126 to your compiled kernel version.
  8. Open modules.dep up with a text editor and do a search & replace. Replace all instances of “kernel/” with “/lib/modules/2.6.22.19-lab126/kernel/” (again, use your version string). I’m not sure this is needed, but better safe then brick.
  9. Now copy arch/arm/boot/uImage, linux-2.6.22.19-lab126.tar.gz (or whatever your version is), and modules.dep to an easy to access location.

Part 3: Installing on Kindle

  1. Connect the Kindle to your computer, and open up the storage device. Copy the three files you moved from the previous part to your Kindle via USB.
  2. This part is mostly commands, so get a root shell to your Kindle, and do the following commands line by line. Again, anywhere the version string “2.6.22.19-lab126” is used, change it to your kernel’s version. Explanation follows.

mv /mnt/us/linux-2.6.22.19-lab126.tar.gz /mnt/us/modules.dep /mnt/us/uImage /tmp

mv /lib/modules /lib/modules.old

cd /tmp & tar xvzf /tmp/linux-2.6.22.19-lab126.tar.gz

mv lib/modules /lib/

chmod 644 modules.dep

mv modules.dep /lib/modules/2.6.22.19-lab126/

/test/flashtools/update-kernel-both uImage

sync

shutdown -r now

Wow, that’s a lot of commands. What did that do? Well, line by line:

  1. Move the files we compiled to the temp folder. That way, we don’t have to clean up.
  2. Back up the old kernel modules
  3. Go to the temp folder and untar the modules
  4. Install the modules
  5. Correct the permissions for the modules.dep file (in case something happened after copying from your computer)
  6. Move the module dependencies list to it’s correct folder.
  7. Flash the kernel (I don’t know why it has to be flashed twice to two different partitions, but if you don’t, it won’t load, maybe sig checks?)
  8. Make sure everything is finished writing
  9. Reboot