A few people have already writen about the Transcend WiFiSD card and its hackability. I wanted to play around with one, so I ordered one online and spent the last few days playing with it. As it had been pointed out, the card is rather insecure, and the scripts in it can be exploited. That is not the route I took. Transcend has a "GPL release package" for the card on their support website. They are not even close to complying with the GPL. I'll cover this later. The relevant part is that the package does have A kernel source. They provide no info on how to build, nor do they provide any configs. This makes it complicated.

The bootloader (u-boot, whose sources Transcend did NOT provide) reads the ramdisk into RAM, reads the kernel into ram, and jumps to it. The sizes are hardcoded in u-boot at 0x300000 bytes (exactly 3MB). This size limitation is rather annoying, since the existing ramdisk is already quite close to the limit, and addinig much more to it will push it over. Removing things from it is also dangerous - since my goal was to not open the card physically, if it does not boot and does not get onto WiFi, there is no way to debug it. Compressing the ramdisk using better compression was not an option either. Their kernel was not built with support for bzip2 or LZMA.

We need a way to flash this thing safely and effectively. Turns out that this job is done for us. The bootloader of the card will detect on boot if four files called "image3", "initramfs3.gz", "mtd_jffs2.bin" and "program.bin" exist, and, if so, load and run "program.bin", which just so happens to be a copy of u-boot (did I meantion that they did not ship the sources?). This u-boot flashes the card's NOR flash with these three pieces: kernel, ramdisk, and the small jffs2 filesystem. The way the card works is rather curious. Almost all of the code is in the ramdisk, but the size limitation must have bit them too. One library is not: "libcrypto.so.0.9.8" - it did not fit. They unpack it (bunzip2) from the jffs2 filesystem at boot into the RAM. The jffs2 filesystem is also where the settings are stored. This actually explains why flashing new firmware erases the settings - the entire NOR flash partition is overwritten with the new image.

Unpacking the existing ramdisk is trivial, just run this command:

sudo sh -c 'mkdir unpacked && cd unpacked && cat ../initramfs3.gz | dd bs=8 skip=1 | gunzip | cpio -i'
The root privileges are needed since otherwise cpio will not be able to create the devnodes under "dev" and when you re-pack the image, it will not work. The actual process of creating a ramdisk is rather simple. Go into a folder containing the files you want to pack and execute the following command:
find . | cpio -o -H newc | gzip -9 > /tmp/a && printf KAGZabcd | tr dcba $(du -b /tmp/a |awk '{for (b = 0; b < 4; b++) {printf "\\%o", $1 % 256; $1 /= 256}}') > /tmp/b && cat /tmp/b /tmp/a > ../initramfs3.gz && rm /tmp/a /tmp/b
(command updated to a better version, by Ralph Corderoy). This will produce a properly formatted ramdisk in the directory above the current one with the proper name. It is your job to ascertain that it is of valid size (less than 3MB) and contains a valid bootable filesystem. But fear not. No matter what you do here, the card remains reflashable! You can add and remove things at will here now.

My first little hack was modifying the boot scripts to create a valid /etc/passwd, put into place a valid private key, and launch a statically-linked copy of ARMv5 dropbear so that I could ssh into the card. This was easy and fit into the space allowed on the card. The jffs2 filesystem is mounted under /mnt/mtd. The SD storage is mounted under /mnt/sd. This is rather strange, because it remains mounted even while mounted externally. That is to say two operating systems (linux in the card and whatever is connected to it externally) both have the same FAT32 filesystem mounted read-write. If this does not scare you, it should - the external filesystem can cache reads and buffer writes at will, so no matter how clever the internal driver is, it can never have the whole picture. The lesson here is do NOT write to /mnt/sd without carefully considering the repercussions. That being said, KA2000 seems to do some clever things in allowing both internal and external users access the flash storage. It DOES get very very upset if you repartition the card or format it with something other then FAT32 - do not do this.

In any case, wanting to run bigger things on the card, and having learned that repartitioning it is a bad idea, I decided to try to loop-mount a file on the flash storage. No joy - ext2/3/4 are also not in the kernel. I tried swap, to see if I could help the card out with its lack of ram - no joy here either - swap support is not enabled in the kernel. In fact, the kernel had nothing of interest enabled at all - no fun for us!

We are left with no choice - we must build our own kernel. So let's dig in. First we need to figure out how the existing kernel is configured. Well, it is not configured with a ".config" file under proc, so no easy answers there. We can check /proc/cpuinfo and see the platform is "KeyASIC 2000" - this is a start. The code for this platform is under arch/arm/mach-ka2000. The makefile betrays to us that the config needed to build for ka2000 is "CONFIG_ARCH_KA2000". Well, now we can see and hope that Transcend shipped a good defconfig for us. A search through arch/arm/configs yields two configs for KA2000: "ka2000" and "ka2000_Trek". Building either one of those does not give us a working WiFiSD card - not good. What now? Clearly Transcend did not ship us the proper config. Luckily, the running kernel has a /proc/kallsyms, so I dumped that, and started messing with the local kernel's options to get it to export at least all the symbols that theirs did. A few things came of this effort: (1) I learned of a few options that their code needed that neither of the ka2000 configs included, and (2) I noticed they had a few modules loaded into their kernel. The modules pose an interesting problem - kernel checks module versions and refuses to load wrong ones. Normally IF TRANSCEND FOLLOWED THE GPL AND SHIPPED THE SOURCES TO THESE MODULES, this would not be an issue. No such sources were shipped, so we are forced to find other ways. The modules loaded are "ka2000_sdio", "ar6000", and "ka2000_sdhc". Only the sources to "ka2000_sdio" are shipped. After turning off module version checking in the kernel config, there was still no luck, so I decided to go into module.c in the kernel source, and completely obliterate any sort of checking it might do at all, to force it to load anything that anyone calls a module. That worked! I finally had the WiFiSD running my own kernel and it was able to load their modules and get onto WiFi. Their bootloader does not support compressed kernels, so you need to make sure to use arch/arm/boot/Image as your kernel (renaming it to "image3" for flashing) and keep it under 3MB.

An exciting time indeed - now this WiFiSD card is a perfectly working ARMv5 computer with a kernel and ramdisk we can build, and 16GB of storage. Pity it only has 32MB of RAM. Well, we do have ability to modify the kernel now. I added support for swap, ext4, sysfs, loop, and a few other modern conveniences we all know and love. Once again the card booted. Now I was able to swapon a file on the SD card, loop-mount a 2GB ext4 filesystem and chroot into a version of ubuntu in there. Once inside, it is the nice and comfy environment you'd expect. I was able to bring up sshd with X-forwarding, and even run firefox on the card (it was slow). Modifying the card's boot scripts again, I tried to get it to do all this on boot and succeeded. SWEET!

The card has a myriad of uses now. Something cool: it will boot and run outside of a valid SDHC host. In fact, aplying power to it is enough. Additionally, it looks no different from a normal SD card, so if the label is removed, it is indistingishable. Uses range from nefarious ("lose" it somewhere and have it upload all files anyone places on it) to humorous (use imagemagic to flip and invert all images placed on it by a digital camera) to useful (upload images automatically to Facebook / G+ / Twitpic / Instagram / $SOCIAL_NETWORK_X direct from card) to gaming-related (a tiny access point for LAN-requiring games in places with no AP), to convenience (install samba - tiny wifi fileshare anyone can use). Cool, right? Only one problem remains:

GPL license protects GPL-licensed projects from people who want to use them but not contribute back the changes. The discussion of the ethics of forcing someone to contribute is beyond the scope of this article, but the effective point is that in the case of u-boot, kernel, and busybox you must provide an offer of the source with any binary distribution, as required by the GPL. GPL also makes anything linked with a GPL sourced component a derivative work - requiring it too to be licenced under GPL. That means that kernel modules (or at least the part of them that contacts the kernel) must be GPL. Apparently Transcend decided against following the license here. Their kernel source does not come with the sources for "ar6000" and "ks2000_sdhc" modules, which violates the GPL. They also did not provide the sources to u-boot. I attempted to email them asking for the sources. The first time I got a reply from a "Customer Service Manager" Marc Crawford, who said that "Regretfully, this product has been discontinued and we no longer sell this card in the United States." My reply stating that that does not necessarily absolve them of the requirements of the license went unnoticed, and no more replies followed. Curiously, in the last two weeks they published an update to the card (v 1.8), which would contradict their statement of no longer supporting/selling it. I tried again, with more details, explaining that they were probably in violation of GPL by not following it, and should probably look into it. I got a reply from a "Technical Support Engineer" Lillian Lopez asking me where I lived. That seemed rather inconsequential, but I answered anyways that I lived in California, USA. What followed was a rather rude reply telling me that they are uninterested and I am "free to report this to any linux organization." Food for thought...

In any case, you can download the relevant pieces from here. Included is a kernel config that will work, replacement module.c file, and a full update that will update your card to 1.6 with a version of my changes (it will openup ssh listening on port 22 on boot, login is root, password is "dmitry.gr_WiFiSD"). The kernel supports loopmounts, so you can have fun with it. Transcend's "GPL release package" can be gotten here(registration required). Latest firmware is 1.8, which is here(registration required). Warning: I have not looked at 1.8 and have no idea what is in there. My firmware is based on version 1.6 from here(registration required).

UPDATE: after my emails to them and them telling me to go away, it appears they did include the u-boot source code in their GPL zip archive quietly. The old file is still up, however, so you can see it here for proof. But still no sources for the modules... Curious...

© 2012-2024