Jump to content

Raw Byte Access to Removable Drive


 Share

Recommended Posts

I'm trying to read raw bytes from a removable drive using the WinAPI functions (_WinAPI_CreateFile, _WinAPI_SetFilePointer, _WinAPI_ReadFile).

Here is the MSDN reference for CreateFile and ReadFile.

My removable drive is mounted at Z:. (But for testing you can probably used a fixed drive like C:. It gives me the same results.)

After some trial and error, I was able to get the CreateFile function to return a (seemingly) valid handle. It seems to work correctly if I enter the drive like this: ".Z:", provided that the share mode includes read/write. (If I don't set the share mode like that, then the returned handle is zero for some reason.) Entering ".PhysicalDrive2" also seems to work, and is also a little more lenient on the share mode.

The problem is that when I pass it to the ReadFile function, it reports zero bytes read and the data seems to be just zeros.

Any ideas?

#RequireAdmin
#AutoIt3Wrapper_UseX64=n
#include <WinAPI.au3>

$sFileName = "\\.\C:";
$iCreation = 2; OPEN_EXISTING
$iAccess = 2; GENERIC_READ
$iShare = 2+4; FILE_SHARE_READ + FILE_SHARE_WRITE

$hFile = _WinAPI_CreateFile($sFileName, $iCreation, $iAccess, $iShare)
If @error Or $hFile = Ptr(0) Then
$str = "Could not open file "&$sfilename&@CRLF
$str &= "Error: "&@error&@CRLF
$str &= "Handle: "&$hFile
MsgBox(0,"Error: _WinAPI_CreateFile",$str)
Exit
EndIf

MsgBox(0,"Success: _WinAPI_CreateFile ","Handle: "&$hFile)

_WinAPI_SetFilePointer($hFile,0); Beginning of file
If @error Then
MsgBox(0,"Error: _WinAPI_SetFilePointer",StringFormat("Could not move pointer. (Error %d)\n",@error))
EndIf

Global $nBytesReceived
$tBuffer = DllStructCreate("byte[512]")

_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer,1), 512, $nBytesReceived)
If @error Then
MsgBox(0,"Error: _WinAPI_ReadFile",StringFormat("Could not read file. (Error %d)\n",@error))
EndIf
If $nBytesReceived<512 Then
MsgBox(0,"Error: _WinAPI_ReadFile",StringFormat("Only %d bytes read.\n",$nBytesReceived))
Else
MsgBox(0,"Success: _WinAPI_ReadFile",StringFormat("Read %d bytes.\n",$nBytesReceived))
EndIf
_WinAPI_CloseHandle($hFile)
$sText = Hex(DllStructGetData($tBuffer,1,1),2);Just the first byte
MsgBox(0,"Result",$sText)
Edited by dpryan
Link to comment
Share on other sites

I finally got this working.

It looks like you need to read in multiples of the blocksize (512 bytes). Offsets must also be a multiple of the blocksize.

For example, reading 1, 2, 511, or 513 bytes all fail. But reading 512 bytes works.

Link to comment
Share on other sites

The only reason that I can figure is that the file is still empty when you try to read it?

Ok, see you got it now.

Also, could you post the working code?

Edited by jaberwocky6669
Link to comment
Share on other sites

Done. I justed edited my OP since the changes were minor.

Note that the original code (with arbitrary read offset amounts) did work if you were to point to a file ("C:test.txt"), but not for raw filesystem and drive accesses (".C:" or ".PhysicalDrive2"). I changed the code to read a block of 512 bytes, and now it works.

Link to comment
Share on other sites

If one want to make the code work on generic drives, then one need to adjust that drive blocksize to what it actually uses. I believe this can easily be done using WMI. Physical blocksize has historically been 512 bytes but modern drives (SSDs and HDs) tend to use 4K. To be safe the code should be prepared to handle any blocksize the drive declares (always a power of 2).

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

@jchd

Good point. I don't really need 4k blocksize support, but I'll look into that. It seems that this dos command will output the relevant info, but there might be an easier way to do it:

wmic partition get BlockSize, StartingOffset, Name, Index

@kylomas

It's useful anytime you want to read raw data outside of a filesystem.

Perhaps you had data on a SD card, but then you accidentally reformatted the drive and you want to recover the data.

Or maybe you want to access data that isn't contained in a file. For example, what does the Master Boot Record (MBR) on your computer look like?

According to the specification, it can be in one of two different formats, but always ends in 0x55AA for the "boot signature."

To read your MBR, try this code (basically the same thing as the original post, but pointing to PhysicalDisk0 and displaying the first 512 bytes):

#RequireAdmin
#AutoIt3Wrapper_UseX64=n
#include <WinAPI.au3>

$sFileName = "\\.\PhysicalDrive0";
$iCreation = 2; OPEN_EXISTING
$iAccess = 2; GENERIC_READ
$iShare = 2+4; FILE_SHARE_READ + FILE_SHARE_WRITE

$hFile = _WinAPI_CreateFile($sFileName, $iCreation, $iAccess, $iShare)
If @error Or $hFile = Ptr(0) Then
$str = "Could not open file "&$sfilename&@CRLF
$str &= "Error: "&@error&@CRLF
$str &= "Handle: "&$hFile
MsgBox(0,"Error: _WinAPI_CreateFile",$str)
Exit
EndIf

MsgBox(0,"Success: _WinAPI_CreateFile ","Handle: "&$hFile)

_WinAPI_SetFilePointer($hFile,0); Beginning of file
If @error Then
MsgBox(0,"Error: _WinAPI_SetFilePointer",StringFormat("Could not move pointer. (Error %d)\n",@error))
EndIf

Global $nBytesReceived
$tBuffer = DllStructCreate("byte[512]")

_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer,1), 512, $nBytesReceived)
If @error Then
MsgBox(0,"Error: _WinAPI_ReadFile",StringFormat("Could not read file. (Error %d)\n",@error))
EndIf
If $nBytesReceived<512 Then
MsgBox(0,"Error: _WinAPI_ReadFile",StringFormat("Only %d bytes read.\n",$nBytesReceived))
Else
    MsgBox(0,"Results",Hex(DllStructGetData($tBuffer,1)))
EndIf
Edited by dpryan
Link to comment
Share on other sites

  • 2 months later...

this example reads the first 512 byte how can i read the hole disk in raw mode and save it to a file?

maybe something like this?

$iSize = _WinAPI_GetFileSizeEx($Src)

While $bytesRead < $iSize

_WinAPI_ReadFile($hFile, DllStructGetPtr($tBuffer, 1), 512, $nBytesReceived)

$bytesRead += $nBytesReceived

Wend

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...