2

I'm trying to get into Qt and as a project I want to try and pull a binary image from a hard drive in Windows. This is what I have:

QFile dsk("//./PhysicalDrive1");
dsk.open(QIODevice::ReadOnly);
QByteArray readBytes = dsk.read(512);
dsk.close();
QFile img("C:/out.bin");
img.open(QIODevice::WriteOnly);
img.write(readBytes);
img.close();

When I run it, it creates the file, but when I view it in a hex editor, it says:

ëR.NTFS    ..........ø..?.ÿ.€.......€.€.ÿç......UT..............ö.......ì§á.Íá.`....ú3ÀŽÐ¼.|ûhÀ...hf.ˈ...f.>..NTFSu.´A»ªUÍ.r..ûUªu.÷Á..u.éÝ..ƒì.h..´HŠ...‹ô..Í.ŸƒÄ.žX.rá;...uÛ£..Á.....Z3Û¹. +Èfÿ.......ŽÂÿ...èK.+Èwï¸.»Í.f#Àu-f.ûTCPAu$.ù..r..h.».hp..h..fSfSfU...h¸.fa..Í.3À¿(.¹Ø.üóªé_...f`..f¡..f.....fh....fP.Sh..h..´BŠ.....‹ôÍ.fY[ZfYfY..‚..fÿ.......ŽÂÿ...u¼..faàø.è.. û.è..ôëý´.‹ð¬<.t.´.»..Í.ëòÃ..A disk read error occurred...BOOTMGR is missing...BOOTMGR is compressed...Press Ctrl+Alt+Del to restart...Œ©¾Ö..Uª

Is there a better way of doing this? I tried running it as admin, but still no dice. Any help would be much appreciated.


Update:

I changed the code a bit. Now if I specify a dd images as the input it writes the image perfectly, but when I try to use a disk as the input it only writes 0x00.

QTextStream(stdout) << "Start\n";

QFile dsk("//./d:");
//QFile dsk("//./PhysicalDrive1");
//QFile dsk("//?/Device/Harddisk1/Partition0");
//QFile dsk("//./Volume{e988ffc3-3512-11e3-99d8-806e6f6e6963}");
//QFile dsk("//./Volume{04bbc7e2-a450-11e3-a9d9-902b34d5484f}");
//QFile dsk("C:/out_2.bin");
if (!dsk.open(QIODevice::ReadOnly))
    qDebug() << "Failed to open:" << dsk.errorString();
qDebug() << "Size:" << dsk.size() << "\n";

// Blank out image file
QFile img(dst);
img.open(QIODevice::WriteOnly);
img.write(0);
img.close();

// Read and write operations
while (!dsk.atEnd())
{
    QByteArray readBytes = dsk.readLine();
    qDebug() << "Reading: " << readBytes.size() << "\n";
    QFile img(dst);
    if (!img.open(QIODevice::Append))
        qDebug() << "Failed to open:" << img.errorString();
    img.write(readBytes);
}
QTextStream(stdout) << "End\n";

I guess the real problem I'm having is how to open a volume with QFile in Windows. I tried a few variants, but to no avail.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
user1777667
  • 97
  • 1
  • 7
  • So what exactly is the problem really? Your program lacks any kind of error reporting though. You assume everything goes alright... What is the size of your binary? Please add .errorString() calls after open/read/write if they fail. Also, "QT" is Quick Time. You are not using that. – László Papp Mar 16 '14 at 05:20
  • When I try to pull the image from the hard drive (a 256MB VHD) the binary file it pulls is only 512B and has the "BOOTMGR is missing" text inside. I'm just trying to find out if I'm pulling the disk incorrectly, or if there's something else I'm missing. – user1777667 Mar 16 '14 at 05:23
  • Thanks, I'll give it a try. qDebug << img.errorString() didn't throw anything (if I'm doing that right). – user1777667 Mar 16 '14 at 05:26
  • It's still giving me 512 with: QByteArray readBytes = dsk.readAll(); – user1777667 Mar 16 '14 at 05:27

2 Answers2

1

New versions of Windows added a rule that you cannot use the raw disk object to access parts of the disk that are owned by a mounted filesystem, even with administrator access.

You can use \\\\.\\PhysicalDrive1 therefore only to read the boot sector, plus any gaps between partitions. Partitions that contain recognized filesystems have to be read via the volume object corresponding to the partition. Or first lock/unmount the filesystem.

See also How to WriteFile to a PhysicalDrive (Windows 7) without getting ERROR_ACCESS_DENIED?

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
0

Right, so your code has several flaws as follows:

  1. It is using hard coded windows paths. This could be appropriate for debugging or an example, but probably not for the final code.

  2. It does not check whether the operations succeed.

  3. It does not print the error strings when the operations fail.

  4. You only read 512 bytes maximum.

  5. You are doing a simple copy when QFile::copy() could do the same.

  6. You do not need to close these descriptors explicitly since it is RAII you work with, not low-level C, luckily.

  7. You may be having the filesystem mounted, and Windows might impose some limitation in that regard. Make sure that filesystems on the physical drive ("D: in your case?") are not mounted if you happen to read from physical drive as opposed to a binary image.

This is the code what I would write if I were you:

// "input.bin" can be replaced with any binary or physical drive
// you wish to back up about your physical drive.
QFile dsk("input.bin");
if (!dsk.open(QIODevice::ReadOnly))
    qDebug() << "Failed to open:" << dsk.errorString();

QFile img("output.bin");
if (!img.open(QIODevice::WriteOnly))
    qDebug() << "Failed to open:" << img.errorString();

QFileInfo fileInfo(dsk.fileName());
qint64 size = fileInfo.size();
for (qint64 bytes = 0; bytes < size, bytes+=data.size()) {
    readBytes = myInputFile.read(chunkSize);
    if (readBytes.isEmpty()) {
        qDebug() << "no data was currently available for reading, or that an error occurred, error string:" << dsk.errorString();
    } else {
        if (img.write(readBytes) != readBytes.size())
            qDebug() << "Failed to write all:" << img.errorString();
    }
}

Theoretically, you could even add this loop if you cannot unmount, provided you are only interested in the file contents itself, but then you are going towards compression:

QDirIterator it("D:/", QDirIterator::Subdirectories);
while (it.hasNext()) {
    // backup each file: it.next()
}

This is probably not what you may want here though, so just mentioning it for completeness.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
László Papp
  • 51,870
  • 39
  • 111
  • 135
  • The chunk read/write is now in place, although it is technically very much unneeded without non-corner case images, nor is it slower, and eventually could be even memory mapped file reading and writing. – László Papp Jun 01 '14 at 01:43
  • @FinalContest: The final code snippet has in it the path `//./PhysicalDrive1`, which never is a filesystem. It quite likely contains multiple partitions, which in turn host filesystems. So I'll change it to iterating all files on a partition (although a real file-based image/backup solution would enable the backup privilege in order to skip ACL checks, and also use shadow copies to handle changes to the drive during imaging) – Ben Voigt Jun 01 '14 at 18:14
  • @AndrewMedico: anything else wrong about the answer why you would still hold the -1? – László Papp Jun 02 '14 at 04:08