release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Search | Go
Wiki > Main > SanDisk > SansaConnect > SansaConnectOriginalFirmware

Software

OS

Zing are using an OS and bootloader from Cadenux "Embedded Linux Solutions". The Sansa Connect runs a modified 2.6.4 kernel (although Nmap reports "Linux 2.4.20 - 2.4.32, Linux-based embedded device"), compiled with GCC v3.4.5. On top of this it uses Busybox and uClibc.

Bootloader

The bootloader is named rrload, which is apparently rrload, again from Cadenux. Strings in the bootloader, and application code, talk of a devkey, which may enable a serial console, rshell etc.

Comparing the actual rrload sourcecode to the binary file available in /bin/removeme/rrload.chopped shows that either the bootloader was either heavily modified or is completely new code. The Connect bootloader accepts only a new image format (srr) instead of the ones supported by rrload (rrbin and Motorolas' srec). It also validates GPG signatures on the firmware files, and has hardware-specific code for HID and power management initialization.

Bootloader remains unchanged by the recovery process. Old Sansa Connect's have bootloader version 24655, the refurbished No-WiFi units seems to have bootloader version 49797. It is unknown whether different versions are available on other customer-available players.

Bootloader menu

Bootloader menu can be accessed either on UART0 which is available on debug connector on the PCB (unpopulated) or through I2C to UART converter connected to dock connector. In order to start bootloader menu press UP (it starts on I2C) or DOWN (it starts on UART0) before pressing power button. There is 30 seconds timeout after which normal boot occurs.

Commands:

Command Comment
boot_auto  
boot  
set Sets string parameter
bset Sets binary parameter
lset Sets longbin parameter
bootin  
kernin  
fsin  
bootw  
paramw  
kernw Writes kernel from RAM to flash
fsw  
boote Erases bootloader
parame Erases parameters (includes bootloader graphics; restored after booting OF)
kerne Erases kernel
fse  
test_iod  
usbcopy  
usbflash  
version Prints bootloader version string
flowon  
flowoff  
devid Prints device id

Identified bugs

  • Signature check completely ignores padding. It only checks if 20 (or 32) SHA1 (or SHA256) least significant bytes of (s**e) mod N matches actual data SHA1 (or SHA256). e is 41 and N is 2048 bit. zsitool replicates this error.
  • Signature packet's MPI (See: RFC4880 5.2.2.) length is not validated. This can lead to stack corruption if MPI length is 4208 (bits) or more as the bootloader's bignum works with integers up to 4200 bits. It is not known if LR on stack can be controlled utilising this error, however it is known that simple buffer overflow is not the case.

User Interface

The UI is written in .NET, running on Mono, along with various shell and LUA scripts. I would speculate this part was written inhouse by Zing. The filesystem integrity (at least partially) is verified by GPG.

WIFI update - it will automatically perform an over the air upgrade using it's WIFI connection. It periodically opens an SSL connection to zing.net, presumably to check for newer versions.

Application update - the windows only "Sansa Connect Device Recovery". This downloads several files from zing.net over SSL, and saves them locally to a hidden folder "RecoveryImages". The files, that we have preserved are:

Filename Size (bytes) Function Version
everest_initrd_ext_prod_1.1.1.50239.srr.e 1783824 filesystem 1.1.1
everest_vmlinux_ext_prod_1.1.1.50239.srr.e 1754960 firmware 1.1.1
yeverest_zap_ota_rel_ext_prod_1.1.1.50371.sig 280 platform signature 1.1.1
yeverest_zap_ota_rel_ext_prod_1.1.1.50371.tar.gz.e 17248792 platform 1.1.1
yeverest_zap_ota_rel_1.1.2.65799.tar.gz 17248924 platform 1.1.2
yeverest_zap_ota_rel_ext_prod_1.1.2.65799.sig 280 platform signature 1.1.2
initrd.srr 1783824 filesystem 1.2.0
vmlinux.srr 1754960 firmware 1.2.0
zap.tar.gz 17240292 platform 1.2.0
zap.sig 280 platform signature 1.2.0

If anyone is interested in obtaining these files contact TomaszMon.

The function names come from the update log. The .srr extension is listed in the rrload documentation as "A RidgeRun inspired format, rrbin is a tagged image binary format used for downloading either executable files or data files such as file systems. This format is very efficient..."

Although the .e files are encrypted, during the recovery process they are transmitted over USB to the Connect in the clear - using USBSnoop I was able to capture logs of the update process, and using grep, sed and perl I was able to convert these into binary files.

The two everest files (filesystem and firmware) were sent first as a single transfer to the Connect (USB ID was 0781:7481) using zsi_fw.exe (which is in cmdline directory of sansa connect recovery tool) - the start of this transfer was a vmlinuz image, followed by a Compressed ROMFS image (look for the "45 3d cd 28" magic string). The ROMFS contains the root filesystem - Busybox, uClibc, init scripts (some in LUA), public GPG keys for verification.

In the /bin/removeme folder we found what seems to be a bootloader flash image, complete with a loading script. The flash image is named rrload.srr.chopped, which is (presumably) the rrload image without the .srr header, as it's dumped directly to flash (cat ./rrload.srr.chopped > /dev/mtd0). Warning: the bootloader is not being written at all during the recovery process nor during normal system operation.

The platform file is then sent (USB ID of 0781:7482) - this is a 17Mb .tar.gz containing LOTS of png images, .NET dlls for the UI, more LUA scripts, XML config files and other binaries (freetype, libcurl, libglib, libjpeg, libssl and Mono). Filemon sugests that platform file is sent using zaprecover.exe (which is in cmdline directory of sansa connect recovery tool), it keeps reading platform file by 497-byte blocks.

Actual recovery can be done from commandline (assuming you've run the "normal" recovery atleast once to download recovery images, and you've put those in cmdline directory, and you're issuing those commands being chdired there):
zsi_fw.exe -w everest_vmlinux_ext_prod_1.1.1.50239.srr.e everest_initrd_ext_prod_1.1.1.50239.srr.e
zaprecover.exe -t 600000 -f yeverest_zap_ota_rel_ext_prod_1.1.1.50371.tar.gz.e yeverest_zap_ota_rel_ext_prod_1.1.1.50371.sig

There is open source zsitool available.

Encrypted files

.e files are encrypted with Blowfish (a patent-free symmetric block cipher, details), using a 192-bit key. Both the key and initialization vector for the cipher are obtained from a SHA-256 hash (details) generated from info on the file:

  • 4-bytes containing the last subversion number from the file, expressed in base-13 (big-endian). For example, given the file everest_initrd_ext_prod_1.1.1.50239.srr.e, the last subver number is 50239, which is 143191 (0x00022F57) in base-13. If this value isn't present it is set to 0x6E0ACCCB (1846201547).
  • 4-bytes containing file size (big-endian). In our example, filesize is 1783824 (0x001B3810).
  • The complete filename of the encrypted file. In our example, "everest_initrd_ext_prod_1.1.1.50239.srr.e".
These are fed in order to the SHA-256 hash function. The first 8 bytes of the resulting hash are the initialization vector for the Blowfish cipher while the last 24 bytes are the key - the file can then be decrypted using the cipher in 64-bit feedback mode. For example, the file everest_initrd_ext_prod_1.1.1.50239.srr.e (1783824 bytes) results in:

  • Key = 0x5928DB44795A317AA37ECE1FAE8EC269FC787E26FFB179ED
  • IV = 0x3DCD5A05A346AC40.

SRR file format

SRR files are straight binary files with an attached 16-bytes header detailing loading information, and a 2048-byte footer containing a GPG signature. Most likely, SRR stands for "Signed RRbin"; it includes the same data RRbin does, plus the GPG signature footer. Otherwise, the format is completely different.

SRR file format
Bytes Name Description
00 - 03 Magic number ID for SRR files - should be 0xAABBFFEE for a valid file
04 - 07 Load address Load address in memory (little endian). This is address of memory buffer, not the flash offset nor flash address.
08 - 11 Entry point Indicates the execution starting address (little endian) -
most of the time (linux kernel, f.ex.) this will match the load address.
For non-executable binaries equals 0xFFFFFFFF
12 - 15 Number of bytes Number of bytes to be sent _(little endian)_
This should be filesize + 2048 bytes for the signature
16 - ... Data

Binary data to load into device
Last 2048 Signature GPG binary signature,
zero-padded

Bootloader will accept file transfer if all of these conditions are met (list is not complete):

  • Load address+Number of bytes does not overflow (32 bit unsigned integer)
  •  <Load address; Load address+Number of bytes> 
    lies within
     <0x1000000; 0x1300180) u (0x131EAF4; 0x1420000) u (0x1440000; 0x5000000> 

Signatures

All the files transferred to the Connect must be signed. Signatures used on all recovery files are 280 bytes long, with the GPG key ID 0xD9F1EC060FA0EFA9 (listed as ""). This is a SHA-1 hash encrypted with RSA using a 2048-bit key. The public key is available on the unencrypted initrd images; currently the private key is unknown. Both the bootoloader and initrd scripts will accept files signed with "" or "ZSIDevKey".

Files transfered via zsi_fw.exe include signatures as a part of the uploaded .SRR file. Platform files need the signature to be sent separately.

Signing keys
Name Public key Private key Comments
 <ZSIProdKey> 
Available on /root/.gnupg Unknown All official recovery files are signed with this key
 ZSIDevKey 
Available on /root/.gnupg Unknown Apparently used to sign developement files
 EverestEnsky <EverestEnsky@ensky.com> 
Available on /root/.gnupg Unknown Use unknown
 <key.FF.manufacturing> 
Available on /root/.gnupg Unknown Use unknown
 <key.FF.transfer> 
Available on /root/.gnupg Available on /root/.gnupg Use unknown

Device ID

All Sansa Connects store a 16 bytes device ID, with the following format. Descriptions are lifted verbatim from /usr/share/lua/5.1/deviceid.lua:

Device ID format
Start byte End byte Size Description
0 1 16 bits Unique for each device model, manufacturer, perhaps revision, etc.
Values for this field will be defined by ZSI and supplied to device manufacturers.
2 3 16 bits Sub format of this field uniquely defined for each device type.
Sample data that might be included are mfg plant, line id, build revision, etc.
This field should be used to make it easy to assure DeviceID uniqueness by it easy to assign field N.
For example, if there are 4 parallel assembly lines, each of which has a station that assigns serial numbers to devices,
the line number should be print encoded in this field so that each serial number assignment sation can chose
a value for field N independently.
4 5 16 bits 14 bit date in days since 1/1/2005 followed by 2 bit shift. Good for 45 years.
This field should be changed every shift, and must be changed every day.
6 11 48 bits Provides uniqueness per device. Method for assuring uniqueness is not specified, but could be:
monotonically incrementing counter; clock-related value that avoids clock reset and wrap problems;
random number generated using a quality random number generator;
UUID or GUID generated using platform services of the manufacturing station which is then
hashed using a quality hash function such as MD-5 or SHA-1 to generate a
pseudo-random number.
12 12 8 bits Indicates which Device Manufacturing Key was used to generate
the Encrypted Device Service Key for the device.
13 15 24 bits A value computed at manufacturing time by passing the other components of the
DeviceID to a library or web service function provided by ZSI. We can evolve the way
we compute this value over time, but initially we will
use this field to make it hard to guess valid DeviceIDs, and easy to confirm
the integrity of a device ID.

zsi_fw.exe - Uploading firmware to device

zsi_fw.exe -w everest_vmlinux_ext_prod_1.1.1.50239.srr everest_initrd_ext_prod_1.1.1.50239.srr
ZSI FW load starting.
Found unencrypted file: everest_vmlinux_ext_prod_1.1.1.50239.srr
Found unencrypted file: everest_initrd_ext_prod_1.1.1.50239.srr
Open USB Device start
found a device!
Attempting to open \\?\usb#vid_0781&pid_7481#5&1b0f9047&0&2#{184954e0-9128-11db-b606-0800200c9a66}
opened device!
completeDeviceName = (\\?\usb#vid_0781&pid_7481#5&1b0f9047&0&2#{184954e0-9128-11db-b606-0800200c9a66})
Opened successfully.
data completeDeviceName = (\\?\usb#vid_0781&pid_7481#5&1b0f9047&0&2#{184954e0-9128-11db-b606-0800200c9a66}\PIPE00)
Opened successfully.
Loading: 1008000 16809984 1754944
Done!
Loading: 4400020 4294967295 1783808
Done!

The upload process simply transfers the given .srr file through USB (ID 0781:7481) - if it's encrypted, it's decrypted on the fly. The program first transfers the 16-bytes header and then the rest of the file in 64-bytes blocks.

zsi_fw.exe - Reading from device

zsi_fw.exe allows reading data from the device - it's invoked in this mode during the recovery process to retreive a device ID. The only parameter that matters is the "-r" switch - the rest is ignored.

c:\Archivos de programa\SanDisk\Sansa Connect Device Recovery\cmdline>zsi_fw.exe -r 4000000 kk
ZSI FW load starting.
Open USB Device start
found a device!
Attempting to open \\?\usb#vid_0781&pid_7481#5&29b63fa7&0&2#{184954e0-9128-11db-b606-0800200c9a66}
opened device!
completeDeviceName = (\\?\usb#vid_0781&pid_7481#5&29b63fa7&0&2#{184954e0-9128-11db-b606-0800200c9a66})
Opened successfully.
data completeDeviceName = (\\?\usb#vid_0781&pid_7481#5&29b63fa7&0&2#{184954e0-9128-11db-b606-0800200c9a66}\PIPE01)
Opened successfully.
ID: 00350cde0cddccfbeb92ec830300348c

In this mode the process reads 32 bytes from the device which are dumped as a string. Transfer type is USB control transfer (request type = 0x00000000, value = 0x0000AAAA, index = 0x0000AAAA)

zaprecover.exe - Writing platform to device

zaprecover.exe writes files to the devices' filesystem.

c:\downloads\Sandisk_Sansa_Connect\test>zaprecover.exe -t 600000 -f yeverest_zap_ota_rel_ext_prod_1.1.1.50371.tar.gz.e yeverest_zap_ota_rel_ext_prod_1.1.1.50371.sig
ZSI FW load starting.
Found encrypted file: yeverest_zap_ota_rel_ext_prod_1.1.1.50371.tar.gz.e
Found unencrypted file: yeverest_zap_ota_rel_ext_prod_1.1.1.50371.sig
found a device!
Attempting to open \\?\usb#vid_0781&pid_7482#5&29b63fa7&0&2#{088db354-111f-11db-9804-b622a1ef5492}
opened device!
completeDeviceName = (\\?\usb#vid_0781&pid_7482#5&29b63fa7&0&2#{088db354-111f-11db-9804-b622a1ef5492}\PIPE01)
found a device!
Attempting to open \\?\usb#vid_0781&pid_7482#5&29b63fa7&0&2#{088db354-111f-11db-9804-b622a1ef5492}
opened device!
completeDeviceName = (\\?\usb#vid_0781&pid_7482#5&29b63fa7&0&2#{088db354-111f-11db-9804-b622a1ef5492}\PIPE00)
...................................................................................................Done!
.Done!

Working around WiFi connection problems

As the zing service has been abandoned, we need to do extra things, to get device connected to wifi. On debian, I've solved this by installing hostapd (but you can skip this, if you have access to OpenWRT or alike based router), apache and dnsmasq. Assuming the hostapd works on interface with ip address 192.168.0.1, configure dnsmasq to give appropiate ip address to sansa connect, enable MASQUERADE:
iptables -A POSTROUTING -t nat -j MASQUERADE -s 192.168.0.0/24
echo 1 > /proc/sys/net/ipv4/ip_forward
Add "192.168.0.1 sandisk.ping.zing.net" to /etc/hosts Set apache to work on that interface, both http (80) and https (443), and write "success" into /var/www/index.html

Open ports

When connected via WIFI, the device has TCP port 8088 open, which appears to be a web server. The headers returned are:

Connection: close
Server: ZING-0035/1.1.1.50239 (xxxx; en-us) ZAP/1.1.1.50371 BOOT/24655 libcurl/7.16.0 OpenSSL/0.9.8a

404 Not Found

where xxxx is the 32 character long hex unique Device ID (visible in the Connect firmware under Settings -> Info -> Software Versions).

Server appears to be written in C++, the executable code for it is located inside assets/System/mono binary. Code located under .text:002442A0 is responsible for displaying "404 Not Found" message.

There don't appear to be any open UDP ports.

The device can be crashed by sending a lot of random data to the open port 8088. Under Linux (substitute 192.168.1.128 for your device's IP address):

dd if=/dev/urandom bs=1 count=100000 | nc 192.168.1.128 8088

Crash can be reproduced every time with the same data, it happens in HTTPServer, crashdump indicates that it crashed inside _ZN8NZString7ToLowerEv which was called by _ZN22NZHTTPServerConnection12HandleHeaderEP8NZString

r5 - 02 Apr 2021 - 20:46:07 - UnknownUser

Copyright © by the contributing authors.