Random things of a random world

Sami's Page

  • Join Us on Facebook!
  • Follow Us on Twitter!
  • LinkedIn
  • Subcribe to Our RSS Feed

Recovering Intel FakeRAID / RST / ISW Contents

I ran into a situation where a laptop with Intel RST / ISW / "FakeRAID" used in stripe mode between two disks had a disk failure. Most things of course were backed up so not a big problem, but some newer files were "nice to get back." So I decided to have a look. It's quite bad to have this kind of system by default in machines, since it will ensure that data is completely gone very easily. If a regular SSD breaks you probably can still get data out of most of the disk. With stripe/RAID 0 a small error in a suitable spot makes it a lot harder since the data is spread out.

The machine only booted into Windows recovery mode and there the only thing that was presented was "no disks in machine" situation. Zero disks. Even though Windows recovery booted from the disks. So there's something quite bad going on.

I booted up Linux. Checked that dmraid should be able to handle Intel FakeRAID properly. Ran dmraid -s and it nicely output information about the RAID setup. Except it couldn't find the second drive. That's kinda a problem.

I checked that the second disk does contain data and can be read. So let's dump everything out! Making images is always the first step since you don't want to make things worse by poking around. And if the memory chips are failing, the more you use them the more probable that something else also breaks.

From the dumps I saw that the Intel RAID info in the end of the disks was just fine. Both actually contained the same data, which was weird. I think there has to be another data block somewhere and that one is broken since dmraid and Intel's own stuff doesn't recognize it.

So, how to get data out? I have two files which are interleaved due to striping, I can't just shove them in since they're not recognized as RAID (funnily, Gnome Disks did recognize both as part of a RAID setup, but can't mount them etc still). We need to interleave the images. But how?

Fortunately dmraid -s told me that stride is 256. No units, no explanation. From digging around it seems this is the amount of blocks per strip. What is a block? Well that has to be assumed (because dmraid can't be bothered to tell it) to be the 512 bytes on a disk block. So let's use that.

I couldn't find a program to interleave files in a quick search so I wrote my own. Just read the images, copy 256 * 512 bytes from one, then from the other, then from the first, then from the second... until it's all done. Simple code. Took time since all I had were HDDs around to handle the amount of data at that moment.

So now I have a proper disk image. Will it work? Was Intel nice enough to do the RAID this simple? The answer... yes. They were. At least in this case. The data was properly split and no offsets were used. I could just interleave it and then give the whole image to a recovery software to look at. And the filesystem is a bit in shambles but we did get some files that were of interest out.

I'm mostly writing this out since I couldn't really find any real information anywhere about this. All info about recovery were "just rebuild it and lose all data" and whatnot. Not a single "it's just a simple split, interleave and off you go, the number to use is this." So maybe this one will help.

And the combiner code is very simple:

using System.IO;

namespace Combiner
{
	class Program
	{
		static void Main(string[] args)
		{
			const int blocksize = 256 * 512;
			string[] filenames = { @"S:\stuff\disk0", @"S:\stuff\disk1" };
			string targetfile = @"F:\wholedisk";
			Stream[] instrs = new Stream[filenames.Length];
			Stream outstr;

			outstr = File.OpenWrite(targetfile);

			for (int i = 0; i < filenames.Length; i++)
				instrs[i] = File.OpenRead(filenames[i]);

			byte[] buffer = new byte[blocksize];
			bool cont = true;

			while (cont)
			{
				foreach (var f in instrs)
				{
					if (f.Read(buffer, 0, blocksize) != blocksize)
						cont = false;
					outstr.Write(buffer, 0, blocksize);
				}
			}

			outstr.Close();
			outstr.Dispose();
		}
	}
}

Add comment

Loading