MRI scan of my brain

I had a MRI today, and afterwards I was given a CD of my scan. The data on the CD was stored in DICOM format, and after some searching I was able to find some open source software to view the data. I especially liked Aeskulap which allowed interactive viewing of the data in multiple dimensions.

I wanted to put my scans online, so I found another set of tools, medcon, that allowed me to convert the DICOM images into png/gif format, and then I used ffmpeg to create the following videos:

I don’t know the exact layout, but on the CD I seemed to have 12 different scans, each with a series of images. The name of the files were all 8 digits numbers, with the first three being the scan number (0 to 11), and the following five digits being (0 to whatever). For example:

DICOM/185723/00000000: DICOM medical imaging data
DICOM/185723/00000001: DICOM medical imaging data
DICOM/185723/00000002: DICOM medical imaging data
...
DICOM/185723/00100000: DICOM medical imaging data
DICOM/185723/00100001: DICOM medical imaging data
DICOM/185723/00100002: DICOM medical imaging data
...

To create videos the first thing I did was to convert the images from DICOM to PNG

sudo apt-get install medcon
mkdir png
for i in DICOM/185723/*; do medcon -f $i -c png -o png/`basename $i`.png ; done;

Now to batch the images I started by creating animated gifs.

sudo apt-get install imagemagick

# Create animated gifs
for i in `seq -w 000 011`; do convert -delay 20 -loop 0 png/$i*.png $i.gif; done;

However, those gifs were huge, up to 20mb. So next I created a set of videos (that were a order of magnitude smaller than the gifs):

sudo apt-get install ffmpeg

# Create MP4
for i in `seq -w 000 011`; do avconv -r 5 -i png/$i%05d.png -r 24 $i.mp4; done;

# Create webm
for i in `seq -w 000 011`; do avconv -r 5 -i png/$i%05d.png -r 24 $i.webm; done;

# Create ogg video
for i in `seq -w 000 011`; do avconv -r 5 -i png/$i%05d.png -r 24 $i.ogg; done;

easy!

Failed Ubuntu update

While trying to do a “do-release-upgrade”, to upgrade to Ubuntu Precise, I encountered a error that Google did not find a satisfactory answer for:

An unresolvable problem occurred while calculating the upgrade:
E:Error, pkgProblemResolver::Resolve generated breaks, this may be caused by held packages.

This can be caused by:
* Upgrading to a pre-release version of Ubuntu
* Running the current pre-release version of Ubuntu
* Unofficial software packages not provided by Ubuntu

If none of this applies, then please report this bug using the command 'ubuntu-bug update-manager' in a terminal.

The problem was I had some packages installed that had no upgrade path, that is, are not available in Precise. To debug this I looked in the /var/log/dist-upgrade/apt.log file, and it identifies the packages that were “broken”. I just had to “apt-get remove” them, do the release upgrade, and afterwards I could reinstall them.

Problem solved.

LaTeX Error: File `layaureo.sty’ not found

I was getting the error ./cv.tex:11: LaTeX Error: File `layaureo.sty' not found. when trying to compile an old tex document of mine.

It seems layaureo is missing from TexLive 2009, the default on Debian at the moment (even though it’s 2012 now!). So I had to install TexLive 2011 from Debian Unstable using Apt Pinning to fix this problem.

Once TexLive 2011 is installed apt-get install -t unstable texlive-lang-italian to bring in the layaureo package.

I also encountered the following problems that was easier to resolve:

LaTeX Error: File `marvosym.sty' not found. solution: apt-get install texlive-fonts-recommended
LaTeX Error: File `fullpage.sty' not found. solution: apt-get install texlive-latex-extra
LaTeX Error: File `multibib.sty' not found. solution: apt-get install texlive-bibtex-extra
LaTeX Error: File `algorithm.sty' not found. solution: apt-get install texlive-science

Hacking Linksys E4200v2 firmware

In a previous post I obtained the Linksys E4200v2 firmware, now I plan to break it apart and see what I can find.

I start off by simplying using “file” on the firmware:

bramp@bramp-laptop:~/linksys/update$ file FW_E4200_2.0.36.126507.SSA 

FW_E4200_2.0.36.126507.SSA: u-boot legacy uImage, Linux-2.6.35.8, Linux/ARM, OS Kernel Image (Not compressed), 2677476 bytes, Thu Dec 22 19:40:21 2011, Load Address: 0x00008000, Entry Point: 0x00008000, Header CRC: 0x6ADD9801, Data CRC: 0xB010442D

Well this is a great start. We know we are dealing with Linux, and that this is a normal uImage. I then move on to use a neat little tool called binwalk. By using libmagic, binwalk tries to find interesting sections of the file.

bramp@bramp-laptop:~/linksys/update$ /usr/local/bin/binwalk FW_E4200_2.0.36.126507.SSA 

DECIMAL   	HEX       	DESCRIPTION
-------------------------------------------------------------------------------------------------------
0         	0x0       	uImage header, header size: 64 bytes, header CRC: 0x6ADD9801, created: Thu Dec 22 19:40:21 2011, image size: 2677476 bytes, Data Address: 0x8000, Entry Point: 0x8000, data CRC: 0xB010442D, OS: Linux, CPU: ARM, image type: OS Kernel Image, compression type: none, image name: Linux-2.6.35.8
1124      	0x464     	LZMA compressed data, properties: 0x87, dictionary size: 250216448 bytes, uncompressed size: 14786800 bytes
16636     	0x40FC    	gzip compressed data, from Unix, last modified: Thu Dec 22 19:40:18 2011, max compression
2752512   	0x2A0000  	JFFS2 filesystem data little endian, JFFS node length: 49
..A whole lot of JFFS2 sections..
20974612  	0x1400C14 	JFFS2 filesystem data little endian, JFFS node length: 51
20974664  	0x1400C48 	JFFS2 filesystem data little endian, JFFS node length: 193

We find a small LZMA section, and large gzip section, and lots of JFFS2 sections. JFFS2 is a popular embedded file system, so we can guess the bulk of the file system is here. Next we can extract each section using dd:

dd bs=1 skip=1124  count=15512   if=FW_E4200_2.0.36.126507.SSA of=image-1.lzma
dd bs=1 skip=16636 count=2735876 if=FW_E4200_2.0.36.126507.SSA of=image-2.gz
dd bs=1 skip=2752512 if=FW_E4200_2.0.36.126507.SSA of=image-3.jffs2

Notice we are using a block size of 1 (so we can count in bytes), and we skip the offset into the file. Then we manually work out the sizes for the lzma and gzip sections. They can be no larger than their start until the next section. If they don’t fill that full space, then not to worry as these tools will normally ignore trailing data.

As I’m interested to see what’s in the JFFS filesystem, we should mount it. You can’t mount JFFS like a normal loopback device, you have to create a fake flash device. The following set of command can solve that:

sudo modprobe mtdram total_size=32768 erase_size=256
sudo modprobe mtdblock
sudo modprobe mtdchar
# sudo mknod /dev/mtdblock0 b 31 0
dd if=image-3.jffs2 of=/dev/mtdblock0
mount -t jffs2 /dev/mtdblock0 /mnt/disk

The mknod line is only needed if you don’t already have a /dev/mtdblock0. Also a /mnt/disk needs to be created ahead of time so the mounting works. Anyway once that was done, I cd /mnt/disk and found that it does appear to contain most of the file system. There are all the HTML pages, and binaries (for example busybox).

Now we should go back to image-1.lzma and image-2.gz. Well straight away trying to decompress image-1

lzma -dc image-1.lzma > image-1
lzma: Decoder error

results in a error. So we can assume that was a incorrectly detected by binwalk. Lets now try and decompress image-2.gz:

gzip -dc image-2.gz > image-2
gzip: image-2.gz: decompression OK, trailing garbage ignored

So that does indeed produce a large image-2 file, so we can ignore the trailing garbage warning. A quick “file” on image-2 doesn’t reveal anything useful, so I run binwalk on it. This turns up a set of false positives. So I take a different approach. I run:

strings image-2

This produces a whole host of valid looking strings. From the contents of the strings it makes me think it’s the actual kernel. A line like this:

Linux version 2.6.35.8 (root@ubuntu) (gcc version 4.2.0 20070413 (prerelease) (CodeSourcery Sourcery G++ Lite 2007q1-21)) #1 Thu Dec 22 16:40:10 PST 2011

helps me come to that conclusion.

I haven’t finished poking around image-2.gz, but I suspect the interesting parts are mostly in the JFFS2 filesystem. Hopefully this will lead to me getting ssh access to the router, and eventually being able to customise the firmware.

Obtaining the firmware for Linksys E4200v2

I recently got a Linksys E4200v2 wireless router. It’s pretty cool, supports IPv6, 2.4Ghz and 5Ghz wifi networks, VPN, etc. The one downside is that the firmware for the router is not available from Linksys’s website, and the GPL code has not been made available, yet… However, the router has been able to pull updates itself from the Internet.

So I wanted to acquire the firmware to see if I could do something fun with the router. I set about to figure out how the router does this. My plan was to set my laptop up between Internet interface on the router, and the cable modem. Since my laptop doesn’t have two network cards, I plugged into a switch and used Ethercap to ARP poison to redirect traffic via the laptop.

Then using Wireshark I could see the traffic coming out of the router. All I needed to do now was to hit the “check for updates button”.

Firstly I saw two DNS requests, one for the AAAA (IPv6) record for update.linksys.com, then a A request for update.linksys.com. Clearly the updates are coming from there. Secondly I saw a HTTPS connection form to that domain. That makes this a little more complex, as I am unable to see the encrypted traffic, and thus see what is being transferred.

So, I grabbed a simple DNS server, and set up a simple SSL server following these instructions.

Now with DNS spoofing, and a fake SSL server, I could intercept encrypted traffic from the router, as long as it does not validate the SSL certificate. Luckily it didn’t check the validity, and thus I was able to capture the request: (BTW Not checking the cert completely defeats the point of using SSL… bad Linksys!).

POST /cds/update HTTP/1.1
Host: update.linksys.com
Accept: */*
Content-Type: text/xml
Content-Length: 573

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <ns:GetFirmwareFromDeviceRequest xmlns:ns="http://cisco.com/schemas">
      <ns:LanguageCode>en</ns:LanguageCode>
      <ns:CountryCode>us</ns:CountryCode>
      <ns:MacAddress>12:34:56:78:90:ab</ns:MacAddress>
      <ns:ModelNo>E4200</ns:ModelNo>
      <ns:HardwareVersion>2</ns:HardwareVersion>
      <ns:CurrentFirmwareVersion>2.0.36.126507</ns:CurrentFirmwareVersion>
    </ns:GetFirmwareFromDeviceRequest>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

and the response:

<soapenv:Envelope
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header/>
  <soapenv:Body>
    <ns:GetFirmwareFromDeviceResponse xmlns:ns="http://cisco.com/schemas">
      <ns:FirmwareList xmlns:ns="http://cisco.com/schemas">
        <ns:Firmware xmlns:ns="http://cisco.com/schemas">
          <ns:Version xmlns:ns="http://cisco.com/schemas">2.0.36.126507</ns:Version>
          <ns:Revision xmlns:ns="http://cisco.com/schemas">D</ns:Revision>
          <ns:ReleaseDate xmlns:ns="http://cisco.com/schemas">2012-01-06T16:48:08Z</ns:ReleaseDate>
          <ns:DownloadURI xmlns:ns="http://cisco.com/schemas">http://download.linksys.com/updates/to0037258865.pdx/FW_E4200_2.0.36.126507.SSA</ns:DownloadURI>
          <ns:DateFormat xmlns:ns="http://cisco.com/schemas">yyyy-MM-dd'T'HH:mm:ss'Z'</ns:DateFormat>
          <ns:Checksum xmlns:ns="http://cisco.com/schemas">1958710861</ns:Checksum>
        </ns:Firmware>
      </ns:FirmwareList>
    </ns:GetFirmwareFromDeviceResponse>
  </soapenv:Body>
</soapenv:Envelope>

(I slightly modified portions of the request and response to hide the identify of my router.).

I might write a script to make fake requests, but until then you can easily create a request with curl:

curl -d @request.raw https://update.linksys.com/cds/update

Then you just extract the DownloadURI and

curl http://download.linksys.com/updates/to0037258865.pdx/FW_E4200_2.0.36.126507.SSA

Voila I now have the firmware. Now I need to figure out what to do with it.