Skip to content
⌘ NSIS Forum Archive

Reading physical drive

25 posts

simplix#

Reading physical drive

Good day!

I'm trying to read a physical drive, but I get an error. Please tell me how to do it?

;File Access Modes
!define GENERIC_READ 0x80000000
!define GENERIC_WRITE 0x40000000
;File Sharing Modes
!define FILE_SHARE_READ 0x00000001
!define FILE_SHARE_WRITE 0x00000002
;File Creation Flags
!define OPEN_EXISTING 3
!define INVALID_HANDLE_VALUE -1

Section Main

StrCpy $3 "\\?\PhysicalDrive0"
System::Call "kernel32::CreateFile(t r3, i ${GENERIC_READ}|${GENERIC_WRITE}, \
i ${FILE_SHARE_READ}|${FILE_SHARE_WRITE}, i 0, i ${OPEN_EXISTING}, i 0, i 0) i .r2"
${If} $2 != ${INVALID_HANDLE_VALUE}
System::Alloc 1
Pop $0

System::Call "kernel32::ReadFile (i r2, i r0, i 1, *i .r4, i 0) ?e"
Pop $5

System::Call "kernel32::GetLastError() i() .r1"
MessageBox MB_ICONINFORMATION|MB_OK "Return code: $5, Error code: $1"

System::Free $0
System::Call "kernel32::CloseHandle(i r2) i.r3"
${Else}
StrCpy $5 "Error: CreateFile failed for \\?\PhysicalDrive0"
${EndIf}

SectionEnd
ReadFile must return non-zero, but it returns 0 and GetLastError returns 80.

Thanks for your help!
Afrow UK#
You've used ?e for your ReadFile call which means $5 contains the last error code already. Calling GetLastError yourself will not return what you expect as something else since your System call (or even the System plug-in itself) will have either cleared or set the last error code. Use i .s on the end of your ReadFile call instead of ?e (or use i .r5 and remove the Pop $5).

Stu
simplix#
Afrow UK, thank you. If I replace it to next code:
     System::Call "kernel32::ReadFile (i r2, i r0, i 1, *i .r4, i 0) i .r5"
MessageBox MB_ICONINFORMATION|MB_OK "Error code: $5"
When "$5" = "error".
jpderuiter#
A physical drive is named: \\.\PhysicalDrive... (so a dot instead of questionmark)
And as you have to escape the backslash, use
StrCpy $3 "\\\\.\\PhysicalDrive0"
Afrow UK#
Originally Posted by jpderuiter View Post
A physical drive is named: \\.\PhysicalDrive... (so a dot instead of questionmark)
And as you have to escape the backslash, use
StrCpy $3 "\\\\.\\PhysicalDrive0"
You don't need to escape the backslashes in NSIS because they don't act as escape characters ($\ does).

Stu
simplix#
Thanks for help.

Originally Posted by Afrow UK View Post
Remove the space after ReadFile and before the (.

Stu
Oh, I totally forgot about it... But return code still 0 (if the function succeeds, the return value is nonzero).
Afrow UK#
I don't think this is possible any more:


What exactly are you trying to do?

Stu
simplix#
I'm trying read drive on WinXP, but function must work on any system. I think this KB does not matter, because there is considered newer systems. In addition exists utilities that successfully read and write drive on any system, but don't have all needed functions, which can be implemented independently.

Originally Posted by Afrow UK View Post
What exactly are you trying to do?
This is for the treatment of drives from viruses in MBR and similar work. Now I use a third-party utility, but its capabilities are not always enough and want the flexibility to manage data.
jpderuiter#
Originally Posted by Afrow UK View Post
You don't need to escape the backslashes in NSIS because they don't act as escape characters ($\ does)
You're right, in NSIS you don't have to escape a backslash.
Anyway, this is where I got the idea of escaping:
Are you a developer who uses NSIS to distribute your application? Are you a Winamp plug-in developer who wants to use NSIS to distribute your plug-in? Have suggestions for other people like you? This is the place.

It seems to have been working for f0rt
Afrow UK#
Originally Posted by jpderuiter View Post
You're right, in NSIS you don't have to escape a backslash.
Anyway, this is where I got the idea of escaping:
Are you a developer who uses NSIS to distribute your application? Are you a Winamp plug-in developer who wants to use NSIS to distribute your plug-in? Have suggestions for other people like you? This is the place.

It seems to have been working for f0rt
You can thank the vBulletin's PHP code tag he used for that.

Stu
Afrow UK#
Originally Posted by simplix View Post
I'm trying read drive on WinXP, but function must work on any system. I think this KB does not matter, because there is considered newer systems. In addition exists utilities that successfully read and write drive on any system, but don't have all needed functions, which can be implemented independently.


This is for the treatment of drives from viruses in MBR and similar work. Now I use a third-party utility, but its capabilities are not always enough and want the flexibility to manage data.
The article was written before 7 and above was available but will likely apply to those operating systems too unless otherwise specified (everything I have found on Google suggests this is the case).

In order to access a disk directly on Vista and above it looks like you will need to be running as LOCAL SYSTEM, e.g. as a Windows service (or you can use PsExec).

Stu
simplix#
Originally Posted by jpderuiter View Post
Anyway, this is where I got the idea of escaping:
Are you a developer who uses NSIS to distribute your application? Are you a Winamp plug-in developer who wants to use NSIS to distribute your plug-in? Have suggestions for other people like you? This is the place.

It seems to have been working for f0rt
My code is based on it. That code work, even if we replace "\\\\.\\" to "\\?\", otherwise handle of CreateFile will be -1.

Originally Posted by Afrow UK View Post
In order to access a disk directly on Vista and above it looks like you will need to be running as LOCAL SYSTEM, e.g. as a Windows service (or you can use PsExec).
There is no difference, the program starts with system privileges or administrator. Tested on WinXP and Win7.

Thank you all for your help, it is very valuable.
Afrow UK#
Does it work on XP but not on 7? Or does it work on neither?

This is the my code (ReadFile fails with 87 - invalid parameter).
Section Main
StrCpy $3 "\\.\PhysicalDrive0"
System::Call "kernel32::CreateFile(t r3, i ${GENERIC_READ}, i 0, i 0, i ${OPEN_EXISTING}, i 0, i 0) i .r2"
${If} $2 != ${INVALID_HANDLE_VALUE}
System::Call "kernel32::ReadFile(i r2, t .r0, i 32, i .r4, i 0) ?e"
Pop $5
DetailPrint "Return code: $5, Return value: $0"
System::Call "kernel32::CloseHandle(i r2) i.r3"
${Else}
DetailPrint "Error: CreateFile failed for \\?\PhysicalDrive0"
${EndIf}
SectionEnd
Stu
simplix#
Originally Posted by Afrow UK View Post
ReadFile fails with 87 - invalid parameter
This code fails with 87 on WinXP and Win7. IMHO parameters of ReadFile is wrong. I got examples here, here and here.
simplix#
I found new exemple here and ReadFile works fine with files, but then I adapted this code to read drive - ReadFile fails.
Afrow UK#
Originally Posted by simplix View Post
This code fails with 87 on WinXP and Win7. IMHO parameters of ReadFile is wrong. I got examples here, here and here.
I tested my code with a file and it works, so 87 must be telling you the handle is invalid. I will do some more tests if I can tonight but how about writing some C code instead? You can be sure you are getting the parameters right then.

Stu
Afrow UK#
Originally Posted by Anders View Post
System::Call "kernel32::ReadFile(i r2, t .r0, i 32, i .r4, i 0) ?e" should probably be *i.r4.
Tried that too. Still get 87.

Stu
simplix#
I found working code in C here (Posted by nullptr: 09 January 2011 at 11:20am), which compiled in RAD Studio and successfully works even on Win7 x64. But still do not understand why it does not work in NSIS.
Anders#
RequestExecutionLevel admin
Section Main
!include LogicLib.nsh
!define GENERIC_READ 0x80000000
!define OPEN_EXISTING 3
!define FILE_SHARE_READ 0x00000001
!define FILE_SHARE_WRITE 0x00000002
!define INVALID_HANDLE_VALUE -1
StrCpy $3 "\\.\C:" ; Using "\\.\PhysicalDrive0" will succeed but it seems ReadFile only gives you a zero filled buffer?
System::Call "kernel32::CreateFile(t r3, i ${GENERIC_READ}, i ${FILE_SHARE_READ}|${FILE_SHARE_WRITE}, i 0, i ${OPEN_EXISTING}, i 0, i 0)i.r2 ?e"
Pop $5
${If} $2 <> ${INVALID_HANDLE_VALUE}
System::Call "kernel32::ReadFile(i r2, m.r0, i 512, *i.r4, i 0)i.r3 ?e" ; A read request < 512 bytes here will fail on my Win8 system
Pop $5
${If} $3 <> 0
DetailPrint "Read $4 bytes, ASCII-Data=$0|"
${Else}
DetailPrint "ReadFile failed: GetLastError=$5"
${EndIf}
System::Call "kernel32::CloseHandle(i r2)"
${Else}
DetailPrint "CreateFile failed: GetLastError=$5"
${EndIf}
SectionEnd
This gives me "...NTFS...".

Writing this type of low-level code with the system plugin is not a good idea, working with binary data or whatever you are reading is painful.

What are you really trying to do? Detect the filesystem type or something else?
simplix#
Anders, thank you very much. The problem was that my request is less 512 bytes.
Originally Posted by Anders View Post
What are you really trying to do?
As I said before, it's for the treatment of MBR viruses. My project antisms.com (for now only in Russian, sorry) written on NSIS, and I thank very much all contributors of this forum.
Anders#
Well, I think it would be much better to write a plugin, I don't see how all that system::call code is going to be manageable when the codebase gets larger...
simplix#
Personally for me, much better to use WinAPI, because I do not know C, and any changes I make in the code immediately, without waiting for the author of the plugin.
Anders#
IMHO you basically have to understand C and the WinAPI to really use the system plugin. You have to be able to transform the function declarations listed on MSDN or in a .h file and convert it to system syntax and you have to understand how C strings work and how pointers work if you are going to be reading anything other than strings from a text file.

Messing with the MBR is not something most people should be doing and certainly not if you don't have a basic understanding of C and it's structure layout/padding semantics and how it differs from the system plugin struct syntax. Also, as you have seen, reading from a disk at this low level might have alignment and/or buffer restrictions, you cannot just treat it as a normal file.

I personally would not trust a MBR tool if I knew it was written in NSIS.