Its over at https://github.com/oldcomputerjunk – enjoy!
I have a disk image of a Windows 2000(!) computer I saved some years ago, and I wanted to run it up to access some software/data saved within.
Now I could of course just loopback mount the NTFS image and access the files, and I was able to successfully do this. However the data I want is unfortunately in a form that I need to export from the software that created it. This requires running up the Windows system.
I have enough hardware stored (hoarded?) to be able to build a suitable system, but if anything was a candidate for virtualisation, this would be it, right?
TL;DR lots of detail follows…
Now just transferring a Windows 2000/XP drive between systems can be a headache enough. Especially when the CPU or motherboard chipsets, are different… in the past this has involved changing hal.dll , editing the registry and removing chipset specific IDE drivers, and of course VGA drivers, etc, etc. I hoped that running in a VM using ‘common’ devices (i440FX, Cirrus VGA) would alleviate some of this.
Before even getting that far though, my disk image was actually a NTFS partition image. Meaning work is needed before even attempting to boot into it. Typically for systems of that era, I expected the NTFS partition would have started at logical sector 63, (or Cylinder 0, Head 1, Sector 1) – and I found myself dealing with Cylinder-Head-Sector (CHS) addresses for the first time in rather a few years! To get the image to boot I had to construct a boot sector and additional sectors, edit the Master Boot Record partition table to point to the partition and concatenate the partition.
In all cases I was working with a copy of the original image. One cant be too careful.
For maximum compatibility I started by purloining a MBR sector from another Windows 2000 install.
The partition record for the first primary partition starts at hex byte 0x1be in sector 0. Of particular interest is the partition starting sector, the ending sector in CHS, and logical sectors:
0001b0 00 00 00 00 00 2c 44 63 74 a5 94 9a 00 00 80 01 >.....,Dct.......< 0001c0 01 00 07 fe ff fd 3f 00 00 00 7e c5 7c 00 00 00 >......?...~.|...< 0001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >................<
Here, 0x1bf contains the starting head, 0x1c0 bits 0-5 are the sector and 0x1c1 and the upper two bits of 0x1c0 comprise the cylinder. Thus, we have C=0,H=1,S=1, which in logical terms is 63.
Aside: the formula for translation is as follows:
LogicalAddress = (NS x NH) x C + (NS x H) + (S-1) where NS = sectors/track and NH = heads/disk
Nominally, as reported by Linux fdisk when executing an arbitrary Xubuntu image inside kvm, we can start by selecting NS=63 and NH=255. Therefore when C/H/S = 0/1/1 –> (0) + (63×1) + (1-1) == 63. Note that sectors are numbered in 1..63 but cylinders and heads in 0..x … sectors count up in sector, head, cylinder order e.g. 0/0/1..0/0/63,0/1/1..0/1/63,0/2/1..0/2/63,0/254/1..0/254/63,1/0/1..1/0/63, etc.
Aside: as I discovered later, the C/H/S size of a disk reported by fdisk can be somewhat arbitrary and vary from the preferred or physical reality. Let alone what the combination of virtual machine host/ / BIOS decide to report it as…
The byte at 0x1c2 is 0×07 which indicates this is an NTFS partition.
The three bytes at 0x1c3 are the CHS address of the last sector.
The four bytes at 0x1c6 is the logical address of the first sector, which is 63
The four bytes at 0x1ca is the size of the partition in sectors.
I had to edit the bytes between 0x1c3 and 0x1cd.
Now my partition image was 3923426304 bytes or 7662942 sectors (sectors being 512 bytes in this case.)
So I had to replace bytes 0x1ca..0x1cd with 0x5e 0xed 0×74 0×00 which is 0x74ed5d or 7662942 in 32-bit in least significant byte (LSB) first ordering.
The tricker bit is in sorting out the C/H/S equivalent. Using what fdisk reported, I needed to work out the end C/H/S address. This would correspond to logical address 63 + 7662942 – 1 (as logical addresses are zero based.) To start with, this is sector 7663004. 7663004 / (63*255) = 476.99…, so our end cylinder is 476. We take the remainder, 7663004 – (476*63*255), or 16064, and divide by our number of sectors, 63. This yields 254 remainder 62. Thus our ending address in C/H/S terms is 476/254/62, except that sector numbers are 1-based, so we need to write 476/254/63 into bytes 0x1c3.
Modified partition entry:
0001b0 80 01 0001c0 01 00 07 fe 7f dc 3f 00 00 00 5e ed 74 00
One thing to take away here is that this legacy partition record in most cases uses the absolute address, because C/H/S addressing in 3 bytes limits us to the first 8GB of the disk (this is a well known limitation in older versions of various operating systems.)
Note also, as the logical address is 32 bits, this is where the 2TB limit of the legacy MBR comes from, and why any drive > 2TB needs to use a GPT partition table to access more than 2TB!
The boot sector was a 512 byte file. I edited the easy way using ghex2. I still needed to fill 62 sectors before the NTFS partition. Then join it all together.
~$ dd of=padding.bin bs=512 count=62 if=/dev/zero
~$ cat mbr.bin padding.bin ntfs_disk.img > test.img
This resulted in a file I could use with kvm.
The acid test was seeing if the geometry edits worked. I booted the KVM guest with xubuntu, and was successfully able to mount and copy files from my appended partition.
As it turns out that was the easy bit.
When I attempted to boot into the NTFS image, I was greeted with “A disk read error occurred.” – not very hopeful. At this stage I wasn’t sure if I had edited the MBR incorrectly, or the problem was with KVM/QEMU. The usual error message I was used to seeing with Windows was “NTLDR missing.” After a bit of trial and error I decided to step through the bootsector with the debugger, to see if it was chaining to Windows properly. (What geek wouldn’t pass up such a chance :-) of course, later confirmed with hex editor, the string ‘A disk read error occurred’ is located in the NTFS boot file. Which would have saved some effort. But then I wouldn’t be writing about how to debug the bootloader, or learning about debugging with QEMU, or applying x86 disassembler skills I hadn’t used for rather a while…)
- Start the virtual machine, and make it stop for single stepping after starting the CPU. The important options here are
Shell1~$ ~/opt/qemu-1.4.2/bin/qemu-system-i386 -boot c -m 256 -enable-kvm -hda disk.img -cpu 486 -no-acpi -s -S
- Start gdb and remotely attach to the VM.
Shell1234567891011121314151617~$ gdbtarget remote localhost:1234set architecture i8086display /i ($cs*16)+$pcstepi # step into the guest BIOS (seabios)stepistepistepistepistepistepistepistepistepistepibr *0x7c00 # set breakpoint in the MBRcont
Now, the multiple
stepi instructions I found I needed to get this to work at all. In theory, according to what documentation I found, after ‘cont’ is executed the debugger should have stopped the VM at the start of the MBR (0x7c00), however there seems to be a timing glitch between KVM and gdb that caused this breakpoint to be ignored. Upgrading to the latest kvm and gdb didn’t help, but by fluke I managed to stop it and realised I had stepped several instructions into the BIOS first.
To streamline this process, which I repeated a few times, I made a gdb script and executed it using
gdb -x script.txt – the script file contains the commands up to ‘cont’ above.
To assist this process, I replaced the MBR code with the code supplied by Debian in the ‘mbr’ package, so that I had source code to follow along with. And I soon discovered, that the geometry was processed correctly, and the problem was indeed Windows.
After a little more detective work, I was able to confirm (as suspected) that the Windows NTFS bootloader was using ‘int13′ calls, and it was unhappy about the fact that I was using heads > 16. Wierd. However, I recalculated the C/H/S addresses assuming 16 heads instead of 254, and shortly thereafter, I was confronted with the weirdly comforting ‘NTLDR missing’ error message!
At this point it was getting (very) late, so I stopped.
Porting a Linux Router
So I just posted what I hope this time are properly formatted patches to the OpenWRT developers mailing list, a set of patches that add support to OpenWRT for the D-link DIR-632-A1 router.
You can see some of my progression on the OpenWRT forum.
This was quite a bit of a journey, as I had a few false starts and along the way crossed a number of different areas in the Linux kernel. The best thing was debugging bit-banging of device registers, which reminds me of hacking on my Commodore 64 many years ago. I have of course had occasion to do such at times professionally, but I have rediscovered my desire to do more low level hacking, and having recently received a Raspberry Pi as a gift and finding use for my leostick from the 2012 linux conf I expect to have plenty of opportunity when I manage to find some more spare time.
Along the way I extended significantly my knowledge of how to work with OpenWRT and build customised images, etc. I added a build guide for this router to the wiki pending acceptance of patches into the main stream; I think this cuts through the useful but verbose documentation elsewhere in the wiki.
When you need a USB-TTL RS232…
and you live 45m from Jaycar, and its 9pm Friday night anyway and you certainly don’t want to wit 3days for Internet delivery from your friendly Aussie electronics suppliers (hello Core electronics!) or a month for some Chinese no-brand on ebay… and you want to hack now!
A crucial part of hacking a router is access to the serial port. These are always at logic level, and in the case of the DIR-632 at 3v3 not 5V, further complicating things. However all I had handy was a USB-RS232 dongle running at proper RS-232 levels, of +/- 12V – so connecting this would be sure to let the smoke out of something…
Now it turns out I have a shedful of what most people would term junk. But usefully this included a tube of MAX232 chips I acquired some years ago. So first, find a handful of resistors and capacitors, and a birdnest later, one logic level to RS232 converter:
There is a leostick there, but it is being used to provide 5V :-) Originally I attempted to use it as a serial relay, but apparently there is a bug in the firmware in the model I have that causes problems with the d0/d1 serial port and thus all I could ever see was junk… (thanks to MarkJ for letting me know)
The circuit is basically as described here (1), but I used 2x 2u2 capactitors in parallel, not having enough 1uF (* I really get into going the whole bush-mechanic-electronics thing!)
However, this doesnt fix the whole problem – the MAX232 is powered by 5V, although I also later found out it may have worked at 3v3 anyway.
I suspect many of the younger maker crowd might not be aware of some trick that can be employed when necessary: you can of course buy a 2cm sized 3v3 to 5v level converter form Jaycar, or from China on ebay, but again I didnt want to wait, and I had a pile of BC547 transistors handy and basic knoweldge of how logic circuits are actually built.
Thus, two transistors and a few resistors later, a logic level converter:
-+-----------------+- 5V | | | Z | Z | Z | Z __ | | __| |__ Z | Z +---------> __ Z __ __ | __| |__ Z |__| | / | |/ +----/\/\/\-----| | |\ | / | \ 4k7 |/ V ---/\/\/\----| | |\ | | \ | v | | | +-----------------+ | | --+-- --- -
(ASCII art FTW!)
Going he other way, I just ran three signal 1N4148 diodes in series, this dropped the line to about 3v5 which managed to not blow anything up with!
And several rather late nights^H^H^H early mornings later:
andrew@atlantis3:~/develop/openwrt/repos/openwrt$ telnet 192.168.1.1
Connected to 192.168.1.1.
Escape character is '^]'.
=== IMPORTANT ============================
Use 'passwd' to set your login password
this will disable telnet and enable SSH
BusyBox v1.19.4 (2013-04-25 20:02:39 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
_______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
BARRIER BREAKER (Bleeding Edge, r36419)
* 1/2 oz Galliano Pour all ingredients into
* 4 oz cold Coffee an irish coffee mug filled
* 1 1/2 oz Dark Rum with crushed ice. Stir.
* 2 tsp. Creme de Cacao
(This is a late night blog entry ‘get it down before it gets forgotten’, mainly in case it is of use to someone, so please excuse the untidyness!)
I had noticed these for some time at JB HiFi for $59 but ignored them, being not touch screen and
not wanting to waste the money for what seemed to be an underwhelming device I didnt need.
However I was browsing the other day and they were 20% off that, so in a ‘what the hell’ moment
I purchased one to experiment with.
The feature list on paper seems reasonable, for some definition of reasonable. At least, compared to what the average Joe would be paying at least $100 for to a walk out the shop with an android device or a Kobo, etc.
The device is TFT LCD 800×480 resolution in 15:9 widescreen with headphone socket, micro USB for charging / connectivity, and is not touch screen, but button driven.
It runs a custom firmware, with MP3 player, video player, calendar, calculator, voice recorder,
and e-reader. I have only tested the e-reader using PDF, and the photo viewer and MP# player.
The device is recommended to work with the Adobe e-reader Windows software and support DRM’d
ebooks but I didnt test with that. It has a TF (mini-sdcard) slot.
In practice when reading a PDF I found it to be significantly sluggish at
rendering the pages. The rendering quality of the fonts found me struggling to read late
at night as well. The test book I used was the free download edition
of “Hacking the X/Box” (http://boingboing.net/2013/03/11/hacking-the-xbox-free-in-hono.html) by Bunnie Huang, who was a keynote speaker at LCA2013.
He released for free as a tribute to Aaron Swartz, and I found it quite the suitable choice to
read whilst attempting to work out if this device was itself hackable in any way.
Pages with pictures could take several seconds to render, which is something I havent
noticed when using the no-brand $65 Android tablet I purchased from ebay for my kids to use.
On the upside, it competently does photo-frame, and the MP3 playback with a choice of equalisers.
It also supports voice record, video play, FM radio calculator and calendar, I didnt bother trying these.
So the list of upsides is quite short.
The UI however is average, and the physical interface downright woeful. There is a lot of lag responding to button presses. The poor quality is most noticeable with MP3, all the buttons seemed to just seek tracks and I couldn’t work out how to control the volume! According to the manual, ‘up’ and ‘down’ (as one might expect)
should control the volume, but it is difficult to do just this without pressing the central
(ok) button at the same time unless you are very careful.
And the usual response to the wrong button is to restart the current song…
The player played music without headphones but at a very low volume.
Can it be hacked?
The intent of my experiment was to try an alternative firmware, such as found at sites like rockbox.org.
Inside, there are three chips, an RK2738 SOC (ARM), and a FLASH and a RAM. However, it seems the RK2738 is a somewhat underwhelming device from a hackability perspective: initial google searching returned a dearth of information.
The Yellowstone / Audiosonic has no firmware tool on an website relatad to either JB or Kmart or either search term.
I did find a RK27 SDK I could download, and multitude of firmware loaders. But none worked!
In theory the device can be switched into a service mode mode where system partitions become accessible, this would allow the ROM to be dumped, etc.
But none of the suggested methods worked.
First method – write a zero length ‘tag’ file in the root directory, and reboot. I tried a variety of
combinations seen on various forums for similar devices, to no avail. (Example: http://forums.rockbox.org/index.php?topic=34081.0 )
Second method – try the firmware tools of various other devices based on the RK2738, but the tools that actually detected the device as a RockChip require it to be in the system mode.
Going by the SDK and some forum posts, it should be possible to switch to system mode by sending
a specially crafted SCSI command (being a mass storage device, SCSI protocol is used over USB.)
But this approach also failed.
Further research on the RK2738 hinted as to whether rockbox (or even some Linux) might work, but
I can’t experiment until I can get it into system mode. It seems the RK2808 or upwards is needed for Android, so I might be left with RockBox: http://www.rockbox.org/wiki/Rockchip27xxPort
The only thing I have left to try, as ‘reboot’ has some ambiguity, is to disconnect the battery and
do a true cold reboot, to see if any of the tag files might have an effect.
Failing this, you can short pins on the ROM. Life however leaves me no time to waste on the above, so this has now turned into yet another rainy day project.
Of note, the device looks identical to the Audiosonic Ereader marketed by Kmart. (http://www.e3style.com/general/eReaders/Audiosonic/ASEET001K-UM_V4_24Aug2012.pdf)
Otherwise, it will have to do duty as a e-reader (until I get sick of the rendering)
media player ( for which I already have my phone for mp3) and higher resolution photo viewer.
A starting point to a lot of information about similar RK devices can be found at http://dtbnguyen.blogspot.com.au/2012/07/if-only-reading-were-easier.html
The trick to making the webcam work:
This assumes of course you have the various ia32- and lib32- packages installed.
This is with a skype 188.8.131.52 deb I made a couple of computer builds ago, so YMMV.
With thanks to: http://community.linuxmint.com/tutorial/view/219