I want to get a handle to a device driver using its name, like \Device\MyDriver. Is it possible to do it without using the symbolic link exposed?
The reason I ask is because I have an ACL applied to the \Device\MyDriver and a different one applied to the symbolic link "MyDriver". The one applied to the symbolic link is very restrictive and doesn't allow anyone to read. While the one applied to the device itself allows Administrators to read from the device.
I tried to use the following code:
const wchar_t* driverName = L"\\\\?\\globalroot\\Device\\MyDriver
HANDLE driver = CreateFile(driverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
However I couldn't get a handle. Any help? Or from user land the only way to get a handle is via the symbolic link?
Related
I am trying to determine whether or not a filesystem is accessible before attaching to it with microsofts minispy example. To keep things short, I am provided a device name path, such as \Device\HarddiskVolume4\. I figured I could use FilterGetDosName to get a root path which would be consistent and then use GetVolumeInformationW to determine whether or not the volume was actually was attached;
BOOL result = GetVolumeInformationW(rootPath, NULL, 0, NULL, NULL, NULL, NULL, 0);
My issue is, however, that if I pull my USB in and out quickly. It gets stuck here as it attempts to get the data but the volume gets disconnected. How do I safely determine whether or not a volume is attached before attaching my minifilter?
There is a function called: GetLogicalDriveStringsW in order to get the path name of a device rather than working with a nonpersistant devicename as stated in OP. After some logic that handles each drive individually and determining differences, so that you can attach to new devices, you use the GetVolumeInformationW(letter.c_str(), NULL, NULL, NULL, NULL, NULL, NULL, NULL);
My other errors that I got when writing this post was unrelated to this issue. Point is: use GetLogicalDriveStringsW and GetVolumeInformationW.
I use following command to locate EFI_USER_MANAGER_PROTOCOL:
Status = gBS->LocateHandle(ByProtocol, &gEfiUserManagerProtocolGuid, NULL, &bufferSizeu, handlesu);
I get EFI_ERROR - EFI_NOT_FOUND.
Now i try to install protocol and then open protocol:
Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, &gEfiUserManagerProtocolGuid, NULL, NULL);
Protocol open successfully and i try to call function current():
Status = users->Current(users, &User);
Computer freezes and no show any errors.
How can I fix it?
To fix the problem you need to check how you call InstallMultipleProtocolInterfaces - it looks like you did not provide the protocol instance (actually you provided NULL). Therefore when you locate the protocol instance you locate what you placed there, i.e. NULL, so your "users" variable is NULL and the system hangs when you use it.
Please find in UEFI spec the description of InstallMultipleProtocolInterfaces:
The first item (after Handle) is always a pointer to the protocol’s GUID, and the second item is always a pointer to the protocol’s interface. These pairs are used to call the boot service InstallProtocolInterface() to add a protocol interface to Handle.
I would do something like:
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gEfiUserManagerProtocolGuid,
&mUserManager,
NULL);
where mUserManager would be your protocol interface structure. Since you own the protocol interface, you can verify if the address of the located protocol points to the actual location of the structure.
I'm trying to create an application which only allows a single instance across all Windows users.
I'm currently doing it by opening a file to write and leaving it open. Is this method safe? Do you know of an alternative method using C?
The standard solution is to create a global mutex during application startup. The first time that the app is started, this will succeed. On subsequent attempts, it will fail, and that is your clue to halt and fail to load the second instance.
You create mutexes in Windows by calling the CreateMutex function. As the linked documentation indicates, prefixing the name of the mutex with Global\ ensures that it will be visible for all terminal server sessions, which is what you want. By contrast, the Local\ prefix would make it visible only for the user session in which it was created.
int WINAPI _tWinMain(...)
{
const TCHAR szMutexName[] = TEXT("Global\\UNIQUE_NAME_FOR_YOUR_APP");
HANDLE hMutex = CreateMutex(NULL, /* use default security attributes */
TRUE, /* create an owned mutex */
szMutexName /* name of the mutex */);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// The mutex already exists, meaning an instance of the app is already running,
// either in this user session or another session on the same machine.
//
// Here is where you show an instructive error message to the user,
// and then bow out gracefully.
MessageBox(hInstance,
TEXT("Another instance of this application is already running."),
TEXT("Fatal Error"),
MB_OK | MB_ICONERROR);
CloseHandle(hMutex);
return 1;
}
else
{
assert(hMutex != NULL);
// Otherwise, you're the first instance, so you're good to go.
// Continue loading the application here.
}
}
Although some may argue it is optional, since the OS will handle it for you, I always advocate explicitly cleaning up after yourself and calling ReleaseMutex and CloseHandle when your application is exiting. This doesn't handle the case where you crash and don't have a chance to run your cleanup code, but like I mentioned, the OS will clean up any dangling mutexes after the owning process terminates.
I'm creating a global semaphore object in a process like this:
CreateSemaphore(NULL, 1, 1, "Global\\bitmap");
now, when I'm trying to open it in a child process (it's a special case of "another process", it's not going to be a child that opens the semaphore created) like this:
bitmapSem = OpenSemaphore(NULL, TRUE, "Global\\bitmap");
the bitmapSem variable equals NULL and I'm getting error 5 (ERROR_ACCESS_DENIED) from GetLastError().
Any ideas?
I must add a clarification to other answers, and a security warning.
First, passing NULL as the lpSemaphoreAttributes argument to ::CreateSemaphore() does not mean no access to anybody; rather, it means that default access control will be assigned. MSDN is crystal clear on that: If this parameter is NULL, the semaphore gets a default security descriptor. The ACLs in the default security descriptor for a semaphore come from the primary or impersonation token of the creator.
Normally, the semaphore can be opened and used by the same user identity. So, if the semaphore is shared by processes running in the same interactive session, or under the same service identity, it may be opened by another process even if created with the default security descriptor. As #hmjd already noted, you must always explicitly call out the right that you want to assert on the semaphore: SYNCHRONIZE|SEMAPHORE_MODIFY_STATE allows both waiting on and releasing it.
Second of all, a word of caution. By granting Everyone full access to the semaphore, as it was suggested above, a security hole for a DoS attack is potentially created. You should consider whether you want arbitrary processes to be able to grab and release the semaphore. Is it intended for unrestricted public use? It is always a good practice to assign minimal, narrowly permitting ACLs to objects. Using SDDL is probably the easiest way to encode a security descriptor, albeit the script itself is not very readable.
The first argument to OpenSemaphore() is documented as:
dwDesiredAccess [in]
The access to the semaphore object. The function fails if the security descriptor of the specified object does not permit the requested access for the calling process. For a list of access rights, see Synchronization Object Security and Access Rights.
In the posted code NULL is specified: which is not documented as having a special meaning. Change to one of the access rights documented at Synchronization Object Security and Access Rights:
bitmapSem = OpenSemaphore(SYNCHRONIZE, TRUE, "Global\\bitmap");
EDIT:
To create a security descriptor that would grant access to Everyone try the following (untested) code:
/* Create a security descriptor that has an an empty DACL, to
grant access to 'Everyone'. */
SECURITY_DESCRIPTOR sd;
if (0 == InitializeSecurityDescriptor(&sd,
SECURITY_DESCRIPTOR_REVISION) ||
0 == SetSecurityDescriptorDacl(&sd,
TRUE,
(PACL)0,
FALSE))
{
/* Failed to create security descriptor. */
}
else
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
HANDLE sh = CreateSemaphore(&sa, 1, 1, "Global\\bitmap");
}
lpSemaphoreAttributes [in, optional]
A pointer to a
SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle
cannot be inherited by child processes.
Pass an LPSECURITY_ATTRIBUTES with an empty DACL and the bInheritHandle member set appropriately as the 1st argument.
An example in VB would be:
'Setup the security descriptor
InitializeSecurityDescriptor SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION
SetSecurityDescriptorDacl SecurityDescriptor, 1, ByVal 0, 0 'Dacl is present and empty
'Setup the security attributes
SecurityAttributes.nLength = Len(SecurityAttributes)
SecurityAttributes.lpSecurityDescriptor = VarPtr(SecurityDescriptor)
SecurityAttributes.bInheritHandle = False
I am developing a COM surrogate object in C, it will be used by my applications to call the UAC elevation dialog for certain actions that require administrative rights.
The plan is to make this it export a function that takes a pointer to a function with a variable number of arguments and executes it in a different context. This way, an application can use this object to perform some actions with admin rights, all they need to do is use that object and pass it a pointer to the function that has to be executed with said rights.
This works partially, calling CoCreateInstance goes fine, the function pointer is passed and my function is executed.
However, when I create an instance of this object using the COM Elevation Moniker archive, and Microsoft's sample code for CoCreateInstanceAsAdmin, problems occur.
Here is the code:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
{
// Manual implementation of CreateInstanceAsAdmin
CComPtr<IBindCtx> BindCtx;
HRESULT hr = CreateBindCtx(0,&BindCtx);
BIND_OPTS3 bo;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.grfMode = STGM_READWRITE;
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
hr = BindCtx->SetBindOptions(&bo);
if (SUCCEEDED(hr))
{
// Use the passed in CLSID to help create the COM elevation moniker string
CComPtr<IMoniker> Moniker;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid,wszCLSID,sizeof(wszCLSID) / sizeof(wszCLSID[0]));
//Elevation:Administrator!new
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (SUCCEEDED(hr))
{
// Create the COM elevation moniker
ULONG ulEaten = 0;
ULONG ulLen = (ULONG)wcslen(wszMonikerName);
LPBC pBindCtx = BindCtx.p;
hr = MkParseDisplayName(pBindCtx,wszMonikerName,&ulEaten,&Moniker);
if (SUCCEEDED(hr) && ulEaten == ulLen)
{
// Use passed in reference to IID to bind to the object
IDispatch * pv = NULL;
hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv);
}
}
}
return hr;
}
Calling CoCreateInstanceAsAdmin fails with "Class not registered".
The object is registered by creating the following registry keys (here's the body of the REG file)
[HKEY_CLASSES_ROOT\COMsurrogate]
#="COMsurrogate Class"
[HKEY_CLASSES_ROOT\COMsurrogate\CurVer]
#="COMsurrogate.1"
[HKEY_CLASSES_ROOT\COMsurrogate\CLSID]
#="{686B6F70-06AE-4dfd-8C26-4564684D9F9F}"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}]
#="COMsurrogate Class"
"LocalizedString"="#C:\\Windows\\system32\\COMsurrogate.dll,-101"
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\ProgID]
#="COMsurrogate.1"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\VersionIndependentProgID]
#="COMsurrogate"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\InprocServer32]
#="#C:\\windows\system32\COMsurrogate.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\NotInsertable]
[HKEY_CLASSES_ROOT\CLSID\{686B6F70-06AE-4dfd-8C26-4564684D9F9F}\Programmable]
I suppose that some registry entries are missing - that's the conclusion I reach when reading the error message. However, this list of registry keys was compiled after exploring the documentation on MSDN and other sites - so I am pretty certain that nothing was missed.
Among the things I've tried to solve this is to implement it via ATL (such that registration is automated). That works, but the problem is that I can't pass a funtion pointer to the MIDL generated function prototype.
I tried to pass it using the VARIANT type:
v.vt = VT_PTR;
void (*myptr)(void);
myptr = &DoTheStuff;
v.byref = myptr;
hr = theElevated->CoTaskExecuter(0, v);
as result I get "Invalid argument type".
Could someone shed some light on the subject? Perhaps what I am trying to achieve is not possible by design?
I believe the issues you are having is by design and that the intent of window's security improvements were to help avoid potential security risks.
Microsoft doesn't really want you to elevate your privileges if it can stop you from doing so. Executing arbitrary functions as a privileged user shouldn't be easy in any way if Windows is even a decently secured system. You might could try impersonating a different user using tokens and getting better access that way, but even then it would be a stretch. If I remember right, user impersonations won't even guarantee that you'll get full access. The best solution in this case is just to use the super user account and properly request the correct privileges.