Identify Physical Boot Disk

Hi,

I’ve been trying for a long time now (several years, in fact) to identify the boot partition on a PC from within Windows.

Currently I have a method that works > 90% and basically covers all the usual multi-disk configurations, etc. But in many fringe cases, this method does not work. Basically, what I do now boils down to enumerating the physical disks and selecting the active partition on drive 0. But on certain systems, disk 0 is not the disk that Windows uses to boot.

In the past, I’ve tried numerous other methods including checking the “SystemPartition” variable which is very often incorrect.

Can anyone offer any advice on how to detect the actual boot disk? I can get the boot partition by checking the active partition on the boot disk, but I don’t know what disk number to look at…

DO_SYSTEM_BOOT_PARTITION

Or just use SystemRoot symlink - it points to where you need.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Hi,
>
> I’ve been trying for a long time now (several years, in fact) to identify the boot partition on a PC from within Windows.
>
> Currently I have a method that works > 90% and basically covers all the usual multi-disk configurations, etc. But in many fringe cases, this method does not work. Basically, what I do now boils down to enumerating the physical disks and selecting the active partition on drive 0. But on certain systems, disk 0 is not the disk that Windows uses to boot.
>
> In the past, I’ve tried numerous other methods including checking the “SystemPartition” variable which is very often incorrect.
>
> Can anyone offer any advice on how to detect the actual boot disk? I can get the boot partition by checking the active partition on the boot disk, but I don’t know what disk number to look at…
>

Maxim S. Shatskih wrote:

DO_SYSTEM_BOOT_PARTITION

Or just use SystemRoot symlink - it points to where you need.

SystemRoot points to the partition that contains Windows. It doesn’t
necessarily point to the boot partition.

In fact, identifying the “boot partition” is not necessarily a trivial
exercise. What if I’m using a third-party boot manager, and that brings
up Windows 7’s boot manager, and from there I redirect to Windows XP?
Which one is the “boot partition”?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Precisely as Tim says, it’s not that simple at all.

I’m *very* close now to a working solution, but I need the “opposite” of IoCreateSymbolicLink. Does anyone know where I can look up the reverse mapping of symlinks in the kernel namespace? e.g. for objects in the object manager with tag “Symb” (which are Symbolic Links created with IoCreateSymbolicLink), how can I get their destination knowing the source?

To further explain:
IoCreateSymbolicLink(&source, &destination) was called. How I can get to ‘source’ knowing ‘destination’ ?

Thanks.

On second thought, if I have ‘source’ (as a handle or text) how can I get ‘destination’ as a text (and not as a handle) in IoCreateSymbolicLink(&source, &destination)?

> IoCreateSymbolicLink(&source, &destination) was called. How I can get to ‘source’ knowing

‘destination’ ?

No ways, except by enumerating the whole namespace tree.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

ZwQuerySymbolicLinkObject


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> On second thought, if I have ‘source’ (as a handle or text) how can I get ‘destination’ as a text (and not as a handle) in IoCreateSymbolicLink(&source, &destination)?
>

In the op’s case a intelligent guess about which names are of interest would
limit this task, but yes you would have to do something like this.

Mark Roddy

On Thu, Jul 29, 2010 at 9:08 AM, Maxim S. Shatskih
wrote:

> > IoCreateSymbolicLink(&source, &destination) was called. How I can get to
> ‘source’ knowing
> >‘destination’ ?
>
> No ways, except by enumerating the whole namespace tree.
>
> –
> Maxim S. Shatskih
> Windows DDK MVP
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Maxim, your ZwQuerySymbolicLinkObject did the trick. Thanks a bunch :slight_smile:
I had started writing some code to enumerate the object namespace, but it was quickly turning into a living hell since I’m actually working in usermode on a normal application in Visual Studio and have to create the definitions for and dynamically load all kernel functions. I was just trying to import the Io* Functions from ntoskrnl.exe when you stepped in :slight_smile:

>living hell since I’m actually working in usermode on a normal application in Visual Studio and have to

create the definitions for and dynamically load all kernel functions.

The proper way is GetProcAddress(GetModuleHandle(“ntdll”), "Name)


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Note that GetProcAddress is the only API call that wants an LPCSTR, that is,
an 8-bit character string, even in a Unicode app. However, GetModuleHandle
wants an LPCTSTR, that is, either a Unicode or ANSI string, because in
Unicode it compiles to GetModuleHandleW and in ANSI it compiles to
GetModuleHandleA. To be Unicode-aware, in application space you want to
make sure tchar.h is included in your build (for most apps, this happens by
default), and the call would be

typedef result_type (callingconvention * TYPENAMEHERE)(args…);

TYPENAMEHERE func;

func = (TYPENAMEHERE)GetProcAddress(GetModuleHandle(_T(“ntdll”)), “name”);

if the function is a WINAPI BOOL SomeName(int x, int y); you would say

typedef BOOL (WINAPI * SomeNameType)(int, int);

SomeNameType SomeName;

SomeName = (SomeNameType)(GetModuleHandle_(T(“ntdll”)), “SomeName”);

if(SomeName == NULL)
// … deal with the situation that the name was not found…

if(SomeName(3, 5))

Note that you would not write

if( (*SomeName)(3, 5) )

because that is the old, obsolete K&R syntax and has not been used since the
first ANSI (later ISO) compliant C compiler was released. It is accepted
only for backward compatibility with existing code and would not be used for
new code.

I generally use the variable name as the same name as the function I’m
using. With some clever #defines and the use of # and ## you can simplify a
lot of the tedium, e.g.,

#define DECLARE_FUNC(name, module) static const name##Type =\
GetProcAddress(GetModuleFileName(_T(#module)), #name)

so I can write, at least in C++ (which is all I use in application space)

DECLARE_FUNC(SomeName, ntdll);

This is an example of what you can do; my own macro system is far more
elaborate and reduces the whole thing to a couple lines of code per
function. Since I’m usually working in C++ and MFC, I can test to see if
the function variable is NULL and if so, I do a throw new
CUndefinedFunctionException (class CUndefinedFunctionException : public
CException {…stuff…} and put enough information into the constructor to
identify the function and module when the catch occurs.

Some day I’m going to figure out how to get all this to work with C++
templates, but that is a project for some later date.
joe

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Thursday, July 29, 2010 12:25 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Identify Physical Boot Disk

living hell since I’m actually working in usermode on a normal application
in Visual Studio and have to
create the definitions for and dynamically load all kernel functions.

The proper way is GetProcAddress(GetModuleHandle(“ntdll”), "Name)


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

> SomeName = (SomeNameType)(GetModuleHandle_(T(“ntdll”)), “SomeName”);

Thanks for this correction. Forgot it while typing.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

At the risk of waxing off-topic…

I wouldn’t bother with using the tchar machinery at all for a new app today. That only ever existed to allow single source builds for win9x (ansi) and winnt (Unicode) binaries. Unless you are really going to do separate builds for win9x nowadays, save yourself the headache of remembering to use tchar/_T everywhere.

Also, be very careful about using the static initializers for GetProcAddress like that. If you then become tempted to also call LoadLibrary and not just GetModuleHandle from a static initializer, your code will violate the API contract for DllMain were it to be used within a dll (as calling LoadLibrary from DllMain is prohibited, and static initializers are invoked from DllMain in a dll).

While we’re dispensing with quasi-OT tidbits, a handy construct for resolving a large number of exports can be patterned thusly:

MyFuncProc MyFunc;
MyOtherFuncProc MyOtherFunc;
OhNoNotAnotherOneProc OhNoNotAnotherOne;

/* … */

struct
{
void * * Ptr; // Pointer to typedef’d function pointer
const char * Symbol; // Associated name of dllexport to resolve
} Symbols =
{
{ (void **) &MyFunc1 , “MyFunc” },
{ (void **) &MyOtherFunc , “MyOtherFunc” },
{ (void **) &OhNoNotAnotherOne, “OhNoNotAnotherOne” }
};

for (size_t i = 0; i < _countof( Symbols ); i += 1)
{
*Symbols[i].Ptr = GetProcAddress( ModuleHandle, Symbols[i].Symbol );

if (*Symbols[i].Ptr == NULL)
{
//
// TODO: Handle API resolution failure as appropriate.
//
}
}

  • S

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Joseph M. Newcomer
Sent: Thursday, July 29, 2010 3:51 PM
To: Windows System Software Devs Interest List
Subject: RE: [ntdev] Identify Physical Boot Disk

Note that GetProcAddress is the only API call that wants an LPCSTR, that is, an 8-bit character string, even in a Unicode app. However, GetModuleHandle wants an LPCTSTR, that is, either a Unicode or ANSI string, because in Unicode it compiles to GetModuleHandleW and in ANSI it compiles to GetModuleHandleA. To be Unicode-aware, in application space you want to make sure tchar.h is included in your build (for most apps, this happens by default), and the call would be

typedef result_type (callingconvention * TYPENAMEHERE)(args…);

TYPENAMEHERE func;

func = (TYPENAMEHERE)GetProcAddress(GetModuleHandle(_T(“ntdll”)), “name”);

if the function is a WINAPI BOOL SomeName(int x, int y); you would say

typedef BOOL (WINAPI * SomeNameType)(int, int);

SomeNameType SomeName;

SomeName = (SomeNameType)(GetModuleHandle_(T(“ntdll”)), “SomeName”);

if(SomeName == NULL)
// … deal with the situation that the name was not found…

if(SomeName(3, 5))

Note that you would not write

if( (*SomeName)(3, 5) )

because that is the old, obsolete K&R syntax and has not been used since the first ANSI (later ISO) compliant C compiler was released. It is accepted only for backward compatibility with existing code and would not be used for new code.

I generally use the variable name as the same name as the function I’m using. With some clever #defines and the use of # and ## you can simplify a lot of the tedium, e.g.,

#define DECLARE_FUNC(name, module) static const name##Type =\
GetProcAddress(GetModuleFileName(_T(#module)), #name)

so I can write, at least in C++ (which is all I use in application space)

DECLARE_FUNC(SomeName, ntdll);

This is an example of what you can do; my own macro system is far more elaborate and reduces the whole thing to a couple lines of code per function. Since I’m usually working in C++ and MFC, I can test to see if the function variable is NULL and if so, I do a throw new CUndefinedFunctionException (class CUndefinedFunctionException : public CException {…stuff…} and put enough information into the constructor to identify the function and module when the catch occurs.

Some day I’m going to figure out how to get all this to work with C++ templates, but that is a project for some later date.
joe

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Maxim S. Shatskih
Sent: Thursday, July 29, 2010 12:25 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Identify Physical Boot Disk

living hell since I’m actually working in usermode on a normal
application
in Visual Studio and have to
create the definitions for and dynamically load all kernel functions.

The proper way is GetProcAddress(GetModuleHandle(“ntdll”), "Name)


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer


This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

“Tim Roberts” wrote in message news:xxxxx@ntdev…
> Maxim S. Shatskih wrote:
>> DO_SYSTEM_BOOT_PARTITION
>>
>> Or just use SystemRoot symlink - it points to where you need.
>
> SystemRoot points to the partition that contains Windows. It doesn’t
> necessarily point to the boot partition.
>
> In fact, identifying the “boot partition” is not necessarily a trivial
> exercise. What if I’m using a third-party boot manager, and that brings
> up Windows 7’s boot manager, and from there I redirect to Windows XP?
> Which one is the “boot partition”?
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.

NT5.x knows the boot disk location from
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\BootDir

Probably this is used only by the computer properties applet that edits
boot.ini.

Regards,
– pa

Pavel A. wrote:

NT5.x knows the boot disk location from
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\BootDir

Probably this is used only by the computer properties applet that edits
boot.ini.

Yes, but what does that mean, exactly? My guess is that’s the location
of the boot.ini or BCD file that resulted in the current Windows
session. Maybe that’s what the original poster wanted, but it might NOT
be the partition that the computer actually fires up when you reboot.

As an example, say that I have C: as my boot partition. Say that I’m
running boot manager software, and I select a Windows 7 partition in
D:. Also say that the BCD setup for that partition includes a “Previous
version of Windows” entry pointing to Windows XP in E:. If I pick that
and boot XP, my guess is that the BootDir will say E:, even though the
machine actually boots to C:.

The question is more complicated than one might expect at first glance.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I used to use the information in HKLM\System\Setup\SystemPartition (which is the same as HKCU\Software\Microsoft\Windows\CurrentVersion\Setup\BootDir, if I’m not mistaken), but discovered it to be incorrect in many cases. For instance, when bootcamp is used, when running from certain virtual machine software in certain cases, when using a non-standard BIOS, when RAID is involved, and so on and so forth.

FYI, I’m the author of EasyBCD [1], and have run into just about all the problems out there regarding the detection of the boot partition. Using any MS APIs or relying on any of the information in the registry has proved to be useless for any serious redistributable software that will consistently provide information about the boot environment.

Tim, with regards to the BCD chainloading NTLDR question - you have to realize that BOOTMGR has not brought the OS into protected memory/virtualized mode. When it launches NTLDR, it has only launched the binary code, but there is no preconfiguration already done. NTLDR does not care where it was launched from, and does its own detection of boot devices. It uses the INT13 (IIRC) BIOS extension to determine the available drives and then loads NTDETECT & boot.ini from what it has determined to be the boot drive. So whether its loaded directly by the BIOS, by BootCamp, by the BCD, etc. has no relevance to the detected boot partition. And the numbers returned by the INT13 extensions and used by NTLDR do not (usually) match up to the \Device\HarddiskX\PartitionY values within Windows.

1: http://neosmart.net/dl.php?id=1

First, I would note that, speaking on “boot disk”, I was meaning SystemRoot disk.

This is more or less easy to find, but the actual boot disk (with boot loader on it) is harder.

Probably it is a good idea to get the BIOS disk numbers, and scan them in this order to find the active partition.

BCD, etc. has no relevance to the detected boot partition. And the numbers returned by the INT13 >extensions and used by NTLDR do not (usually) match up to the \Device\HarddiskX\PartitionY values

They are 100% different, especially given that \Device\Harddisk%d\Partition0 number is not guaranteed to be persistent across boots. This latter one is “storage device number” for a disk.

If you need int13h (BIOS) numbers, scan the \ArcName object dir, where you will have the paths in the same format as in boot.ini file. The rdisk(%d) number in them is the BIOS disk number.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

> Using any MS APIs or relying on any of the information in the registry has

proved to be useless for any serious
redistributable software that will consistently provide information about
the boot environment.

This can mean that booted OS simply does not have enough information
about its boot environment, and it does not really need it.

Moveover, some serious software, such as TrueCrypt,
by intention obscures the boot path.
One who tries to track the boot partition from outside, will likely end with
the decoy OS.
The real boot path can contain elements invisible from the booted OS.

Regards,
– pa

wrote in message news:xxxxx@ntdev…
> I used to use the information in HKLM\System\Setup\SystemPartition (which
> is the same as
> HKCU\Software\Microsoft\Windows\CurrentVersion\Setup\BootDir, if I’m not
> mistaken), but discovered it to be incorrect in many cases. For instance,
> when bootcamp is used, when running from certain virtual machine software
> in certain cases, when using a non-standard BIOS, when RAID is involved,
> and so on and so forth.
>
> FYI, I’m the author of EasyBCD [1], and have run into just about all the
> problems out there regarding the detection of the boot partition. Using
> any MS APIs or relying on any of the information in the registry has
> proved to be useless for any serious redistributable software that will
> consistently provide information about the boot environment.
>
> Tim, with regards to the BCD chainloading NTLDR question - you have to
> realize that BOOTMGR has not brought the OS into protected
> memory/virtualized mode. When it launches NTLDR, it has only launched the
> binary code, but there is no preconfiguration already done. NTLDR does not
> care where it was launched from, and does its own detection of boot
> devices. It uses the INT13 (IIRC) BIOS extension to determine the
> available drives and then loads NTDETECT & boot.ini from what it has
> determined to be the boot drive. So whether its loaded directly by the
> BIOS, by BootCamp, by the BCD, etc. has no relevance to the detected boot
> partition. And the numbers returned by the INT13 extensions and used by
> NTLDR do not (usually) match up to the \Device\HarddiskX\PartitionY values
> within Windows.
>
> 1: http://neosmart.net/dl.php?id=1
>