Sign in to follow this  
Followers 0
dpryan

Raw Byte Access to Removable Drive

9 posts in this topic

#1 ·  Posted (edited)

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

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

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

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

dpryan,

This is interesting, but I'm afraid I'm missing it's usefulness. Would you mind enlightening me?

kylomas

edit:spelling

Edited by kylomas

Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
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)

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

@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

Share this post


Link to post
Share on other sites

dpryan,

Thanks, I thought it might have to do with recovery but was'nt sure.

kylomas


Forum Rules         Procedure for posting code

"I like pigs.  Dogs look up to us.  Cats look down on us.  Pigs treat us as equals."

- Sir Winston Churchill

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
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
Sign in to follow this  
Followers 0