dpryan Posted January 3, 2013 Posted January 3, 2013 (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?expandcollapse popup#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 January 4, 2013 by dpryan
dpryan Posted January 4, 2013 Author Posted January 4, 2013 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.
jaberwacky Posted January 4, 2013 Posted January 4, 2013 (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 January 4, 2013 by jaberwocky6669 Helpful Posts and Websites: AutoIt3 Variables and Function Parameters MHz | AutoIt Wiki | Using the GUIToolTip UDF BrewManNH | Can't find what you're looking for on the Forum?
dpryan Posted January 4, 2013 Author Posted January 4, 2013 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.
kylomas Posted January 4, 2013 Posted January 4, 2013 (edited) dpryan, This is interesting, but I'm afraid I'm missing it's usefulness. Would you mind enlightening me? kylomas edit:spelling Edited January 4, 2013 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
jchd Posted January 4, 2013 Posted January 4, 2013 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 hereRegExp tutorial: enough to get startedPCRE 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)
dpryan Posted January 7, 2013 Author Posted January 7, 2013 (edited) @jchdGood 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@kylomasIt'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):expandcollapse popup#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 January 7, 2013 by dpryan
kylomas Posted January 7, 2013 Posted January 7, 2013 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
bladem2003 Posted March 11, 2013 Posted March 11, 2013 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
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now