Logical drives are specified by the drive letter and a colon (e.g. "C:").
Physical disk drives are specified by "PhysicalDriveN" where N is for its zero-based index (e.g. "PhysicalDrive0").
The sector to be dumped is specified by a zero-based index.
The macro writes the hexadecimal expression of the bytes as two hex digits each in separate lines.
The size of raw data read from a drive must be aligned to the size of a sector. You don't have to worry, the code will determine the sector size.
System drives require elevated execution.
Steffen
Code: Select all
@echo off &setlocal
:: NOTE: Run as Administrator!
:: Ensure that the script path is the current directory when elevated.
cd /d "%~dp0"
:: Initialize the drivedump macro.
call :init_drivedump
:: Read the second sector (index 1) of the logical drive "C:" and write the HEX
:: dump into the console window.
%drivedump% "C:" 1
echo errorlevel %errorlevel%
pause
:: Read the first sector (index 0) of the physical drive "PhysicalDrive0" and
:: redirect the HEX dump into a file. The parentheses are critical.
>"dump_0.txt" (%drivedump% "PhysicalDrive0")
echo errorlevel %errorlevel%
pause
:: See how many hex bytes (lines) we have in the dump file. This should always
:: be the size of a sector (usually 512).
for %%i in ("dump_0.txt") do set /a "hexbytes=%%~zi/4"
echo hexbytes %hexbytes%
pause
:: Formatting is easy because we have every byte in a separate line. E.g.:
:: Concatenate all hex bytes of the dumped sector into a contiguous string.
setlocal EnableDelayedExpansion
set "hexstr="
<"dump_0.txt" (
for /l %%i in (1 1 %hexbytes%) do (
set /p "ln="
set "hexstr=!hexstr!!ln!"
)
)
echo !hexstr!
endlocal
pause
:: clean up
del "dump_0.txt"
exit /b
:init_drivedump
:: -- BRIEF --
:: Create a HEX dump of a sector of a drive. Each hexadecimal expression of a
:: byte consists of two digits and is written to a new line.
:: NOTE: Certain drives require the script to be executed as Administrator.
:: -- SYNTAX --
:: %drivedump% "drive" [sector_index]
:: drive Logical drive (such as "C:"), or physical disk drive (such
:: as "PhysicalDrive0").
:: sector_index (optional) Zero-based index of the sector to be read.
:: Default index is 0.
:: -- RETURN --
:: 0 The HEX dump has been created.
:: 1 The HEX dump has not been created.
:: -- EXAMPLE --
:: %drivedump% "C:" 0
setlocal DisableDelayedExpansion
set drivedump=for %%- in (1 2) do if %%-==2 (^
%=% for /f "tokens=1,2" %%. in ("^^!p^^! 0") do endlocal^&powershell.exe -nop -ep Bypass -c ^"^
%===% $w=Add-Type -Name pInv -PassThru -MemberDefinition '^
%=====% [DllImport(\"kernel32.dll\")] public static extern IntPtr CreateFile(string name,int acc,int share,IntPtr sec,int how,int flags,IntPtr nil);^
%=====% [DllImport(\"kernel32.dll\")] public static extern int DeviceIoControl(IntPtr h,int ctrl,IntPtr i,int iSiz,int[] o,int oSiz,ref int cb,IntPtr nil);^
%=====% [DllImport(\"kernel32.dll\")] public static extern int SetFilePointerEx(IntPtr h,Int64 mov,IntPtr nil,int start);^
%=====% [DllImport(\"kernel32.dll\")] public static extern int ReadFile(IntPtr h,byte[] o,int siz,ref int cb,IntPtr nil);^
%=====% [DllImport(\"kernel32.dll\")] public static extern void CloseHandle(IntPtr h);';^
%===% $p0=[IntPtr]::Zero;$geo=New-Object int[] 6;$cb=0;^
%===% $d=$w::CreateFile(\"\\.\%%~.\",0x80000000,7,$p0,3,0,$p0);^
%===% if($d -eq [IntPtr]-1){exit 1}^
%===% if(-not $w::DeviceIoControl($d,458752,$p0,0,$geo,24,[ref]$cb,$p0)){$w::CloseHandle($d);exit 1}^
%===% $b=New-Object byte[] $geo[5];^
%===% if(-not $w::SetFilePointerEx($d,[Int64]%%~/*$geo[5],$p0,0) -or -not $w::ReadFile($d,$b,$geo[5],[ref]$cb,$p0)){$w::CloseHandle($d);exit 1}^
%===% $w::CloseHandle($d);^
%===% ($b^^^^^^^|foreach{$_.ToString('X2')}) -join \"`r`n\";exit 0^"^
%=% ) else setlocal EnableDelayedExpansion^&set p=
endlocal&set "drivedump=%drivedump%"
if !!# neq # set "drivedump=%drivedump:^^!=!%"
exit /b
:: The macro wraps Win32 API functions in a PowerShell code. Those functions are
:: capable to get information about a drive, and read raw data of a sector.
:: A few words about abstruse things in the macro code:
:: Array geo is a substitude for the DISK_GEOMETRY structure,
:: geo[5] represents the BytesPerSector member.
:: Magic numbers used:
:: - CreateFile() function
:: 0x80000000 GENERIC_READ
:: 7 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
:: 3 OPEN_EXISTING
:: - DeviceIoControl() function
:: 458752 IOCTL_DISK_GET_DRIVE_GEOMETRY
:: 24 size of geo in bytes
:: - SetFilePointerEx() function
:: 0 FILE_BEGIN