[core] list potentially blocking processes on disk access error

* Using functionality from Process Hacker:
  https://github.com/processhacker2/processhacker2/
* Part of the #773 enhancement
* Also fix minor MinGW and WDK warnings
This commit is contained in:
Pete Batard 2017-04-27 23:06:42 +01:00
parent 27bc4cb02b
commit d5f6ddb653
16 changed files with 654 additions and 26 deletions

View File

@ -210,6 +210,7 @@
<ClCompile Include="..\pki.c" />
<ClCompile Include="..\rufus.c" />
<ClCompile Include="..\checksum.c" />
<ClCompile Include="..\search.c" />
<ClCompile Include="..\smart.c" />
<ClCompile Include="..\stdfn.c" />
<ClCompile Include="..\stdio.c" />
@ -225,6 +226,7 @@
<ClInclude Include="..\format.h" />
<ClInclude Include="..\hdd_vs_ufd.h" />
<ClInclude Include="..\missing.h" />
<ClInclude Include="..\search.h" />
<ClInclude Include="..\settings.h" />
<ClInclude Include="..\libcdio\cdio\cdio.h" />
<ClInclude Include="..\libcdio\cdio\iso9660.h" />

View File

@ -75,6 +75,9 @@
<ClCompile Include="..\dev.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\search.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\rufus.h">
@ -143,6 +146,9 @@
<ClInclude Include="..\db.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\search.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\res\rufus.ico">

View File

@ -193,6 +193,7 @@
<ClCompile Include="..\pki.c" />
<ClCompile Include="..\rufus.c" />
<ClCompile Include="..\checksum.c" />
<ClCompile Include="..\search.c" />
<ClCompile Include="..\smart.c" />
<ClCompile Include="..\stdfn.c" />
<ClCompile Include="..\stdio.c" />
@ -208,6 +209,7 @@
<ClInclude Include="..\format.h" />
<ClInclude Include="..\hdd_vs_ufd.h" />
<ClInclude Include="..\missing.h" />
<ClInclude Include="..\search.h" />
<ClInclude Include="..\settings.h" />
<ClInclude Include="..\libcdio\cdio\cdio.h" />
<ClInclude Include="..\libcdio\cdio\iso9660.h" />

View File

@ -75,6 +75,9 @@
<ClCompile Include="..\dev.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\search.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\rufus.h">
@ -143,6 +146,9 @@
<ClInclude Include="..\db.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\search.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\res\rufus.ico">

View File

@ -11,8 +11,8 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V))
$(AM_V_WINDRES) $(AM_RCFLAGS) -i $< -o $@
rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
net.c parser.c pki.c rufus.c search.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \
libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid
libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid -lpsapi

View File

@ -93,10 +93,10 @@ am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \
rufus-format.$(OBJEXT) rufus-icon.$(OBJEXT) \
rufus-iso.$(OBJEXT) rufus-localization.$(OBJEXT) \
rufus-net.$(OBJEXT) rufus-parser.$(OBJEXT) rufus-pki.$(OBJEXT) \
rufus-rufus.$(OBJEXT) rufus-smart.$(OBJEXT) \
rufus-stdfn.$(OBJEXT) rufus-stdio.$(OBJEXT) \
rufus-stdlg.$(OBJEXT) rufus-syslinux.$(OBJEXT) \
rufus-vhd.$(OBJEXT)
rufus-rufus.$(OBJEXT) rufus-search.$(OBJEXT) \
rufus-smart.$(OBJEXT) rufus-stdfn.$(OBJEXT) \
rufus-stdio.$(OBJEXT) rufus-stdlg.$(OBJEXT) \
rufus-syslinux.$(OBJEXT) rufus-vhd.$(OBJEXT)
rufus_OBJECTS = $(am_rufus_OBJECTS)
rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ms-sys/libmssys.a \
syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
@ -271,12 +271,12 @@ AM_V_WINDRES_1 = $(WINDRES)
AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY))
AM_V_WINDRES = $(AM_V_WINDRES_$(V))
rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
net.c parser.c pki.c rufus.c search.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \
libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid
libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid -lpsapi
all: all-recursive
@ -416,6 +416,12 @@ rufus-rufus.o: rufus.c
rufus-rufus.obj: rufus.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-rufus.obj `if test -f 'rufus.c'; then $(CYGPATH_W) 'rufus.c'; else $(CYGPATH_W) '$(srcdir)/rufus.c'; fi`
rufus-search.o: search.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-search.o `test -f 'search.c' || echo '$(srcdir)/'`search.c
rufus-search.obj: search.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-search.obj `if test -f 'search.c'; then $(CYGPATH_W) 'search.c'; else $(CYGPATH_W) '$(srcdir)/search.c'; fi`
rufus-smart.o: smart.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-smart.o `test -f 'smart.c' || echo '$(srcdir)/'`smart.c

View File

@ -127,8 +127,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
if ((safe_strlen(Path) < 5) || (Path[0] != '\\') || (Path[1] != '\\') || (Path[3] != '\\'))
goto out;
// Resolve a device path, so that users can seek for it in Process Explorer
// in case of access issues.
// Resolve a device path, so that we can look for that handle in case of access issues.
if (QueryDosDeviceA(&Path[4], DevPath, sizeof(DevPath)) == 0)
strcpy(DevPath, "???");
@ -151,6 +150,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
// If we can't seem to get a hold of the drive for some time,
// try to enable FILE_SHARE_WRITE...
uprintf("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");
SearchProcess(DevPath, TRUE, TRUE);
bWriteShare = TRUE;
}
Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
@ -161,7 +161,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
}
if (bWriteAccess) {
uprintf("Opened %s [%s] for write access\n", Path, DevPath);
uprintf("Opened %s [%s] for write access", Path, DevPath);
}
if (bLockDrive) {
@ -177,7 +177,10 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
Sleep(DRIVE_ACCESS_TIMEOUT/DRIVE_ACCESS_RETRIES);
}
// If we reached this section, either we didn't manage to get a lock or the user cancelled
uprintf("Could not get exclusive access to %s [%s]: %s\n", Path, DevPath, WindowsErrorString());
uprintf("Could not get exclusive access to %s: %s", Path, WindowsErrorString());
// See if we can tell the user what processes are accessing the drive
if (!IS_ERROR(FormatStatus))
SearchProcess(DevPath, TRUE, TRUE);
safe_closehandle(hDrive);
}

View File

@ -84,6 +84,10 @@ const char* additional_copyrights =
"http://www.codeguru.com/forum/showthread.php?p=1951973\\line\n"
"Public Domain\\line\n"
"\\line\n"
"Handle search & process enumeration from Process Hacker by wj32 & dmex:\\line\n"
"http://processhacker.sourceforge.net/\\line\n"
"GNU General Public License (GPL) v3 or later\\line\n"
"\\line\n"
"Decompression support from BusyBox/Bled:\\line\n"
"http://www.busybox.net/\\line\n"
"https://github.com/pbatard/bled\\line\n"

View File

@ -31,6 +31,9 @@
#include <share.h>
#include <fcntl.h>
#include <io.h>
#if !defined(DDKBUILD)
#include <psapi.h>
#endif
#pragma once
#if defined(_MSC_VER)
@ -125,6 +128,31 @@ static __inline wchar_t* utf8_to_wchar(const char* str)
return wstr;
}
/*
* Converts an non NUL-terminated UTF-16 string of length len to UTF8 (allocate returned string)
* Returns NULL on error
*/
static __inline char* wchar_len_to_utf8(const wchar_t* wstr, int wlen)
{
int size = 0;
char* str = NULL;
// Find out the size we need to allocate for our converted string
size = WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, NULL, 0, NULL, NULL);
if (size <= 1) // An empty string would be size 1
return NULL;
if ((str = (char*)calloc(size, 1)) == NULL)
return NULL;
if (WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, str, size, NULL, NULL) != size) {
sfree(str);
return NULL;
}
return str;
}
static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments)
{
@ -554,6 +582,24 @@ static __inline DWORD GetModuleFileNameU(HMODULE hModule, char* lpFilename, DWOR
return ret;
}
#if !defined(DDKBUILD)
static __inline DWORD GetModuleFileNameExU(HANDLE hProcess, HMODULE hModule, char* lpFilename, DWORD nSize)
{
DWORD ret = 0, err = ERROR_INVALID_DATA;
// coverity[returned_null]
walloc(lpFilename, nSize);
ret = GetModuleFileNameExW(hProcess, hModule, wlpFilename, nSize);
err = GetLastError();
if ((ret != 0)
&& ((ret = wchar_to_utf8_no_alloc(wlpFilename, lpFilename, nSize)) == 0)) {
err = GetLastError();
}
wfree(lpFilename);
SetLastError(err);
return ret;
}
#endif
static __inline DWORD GetFullPathNameU(const char* lpFileName, DWORD nBufferLength, char* lpBuffer, char** lpFilePart)
{
DWORD ret = 0, err = ERROR_INVALID_DATA;

View File

@ -3469,3 +3469,11 @@ out:
return 0;
}
// The old WDK is showing its age and becoming a pain to support
#if defined(DDKBUILD)
BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf) {
uprintf("NOTE: Process search is not implemented on this platform");
return FALSE;
}
#endif

View File

@ -498,6 +498,7 @@ extern BOOL IsCurrentProcessElevated(void);
extern char* GetCurrentMUI(void);
extern BOOL SetFormatPromptHook(void);
extern void ClrFormatPromptHook(void);
extern BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf);
DWORD WINAPI FormatThread(void* param);
DWORD WINAPI SaveImageThread(void* param);

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 376
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 2.15.1094"
CAPTION "Rufus 2.15.1095"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -334,8 +334,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,15,1094,0
PRODUCTVERSION 2,15,1094,0
FILEVERSION 2,15,1095,0
PRODUCTVERSION 2,15,1095,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -352,13 +352,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.15.1094"
VALUE "FileVersion", "2.15.1095"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.15.1094"
VALUE "ProductVersion", "2.15.1095"
END
END
BLOCK "VarFileInfo"

358
src/search.c Normal file
View File

@ -0,0 +1,358 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Search functionality for handles
*
* Modified from Process Hacker:
* https://github.com/processhacker2/processhacker2/
* Copyright © 2009-2016 wj32
* Copyright © 2017 dmex
* Copyright © 2017 Pete Batard <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
#include <windows.h>
#include "rufus.h"
#include "search.h"
#include "missing.h"
#include "msapi_utf8.h"
PF_TYPE_DECL(NTAPI, PVOID, RtlCreateHeap, (ULONG, PVOID, SIZE_T, SIZE_T, PVOID, PRTL_HEAP_PARAMETERS));
PF_TYPE_DECL(NTAPI, PVOID, RtlAllocateHeap, (PVOID, ULONG, SIZE_T));
PF_TYPE_DECL(NTAPI, BOOLEAN, RtlFreeHeap, (PVOID, ULONG, PVOID));
PF_TYPE_DECL(NTAPI, NTSTATUS, NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG));
PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryObject, (HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG));
PF_TYPE_DECL(NTAPI, NTSTATUS, NtDuplicateObject, (HANDLE, HANDLE, HANDLE, PHANDLE, ACCESS_MASK, ULONG, ULONG));
PF_TYPE_DECL(NTAPI, NTSTATUS, NtOpenProcess, (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID));
PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE));
PVOID PhHeapHandle = NULL;
/*
* Convert an NT Status to an error message
*
* \param Status An operattonal status.
*
* \return An error message string.
*
*/
static char* NtStatusError(NTSTATUS Status) {
static char unknown[32];
switch (Status) {
case STATUS_UNSUCCESSFUL:
return "Operation Failed";
case STATUS_NOT_IMPLEMENTED:
return "Not Implemented";
case STATUS_BUFFER_OVERFLOW:
return "Buffer Overflow";
case STATUS_INVALID_HANDLE:
return "Invalid Handle.";
case STATUS_INVALID_PARAMETER:
return "Invalid Parameter";
case STATUS_NO_MEMORY:
return "Not Enough Quota";
case STATUS_ACCESS_DENIED:
return "Access Denied";
case STATUS_BUFFER_TOO_SMALL:
return "Buffer Too Small";
case STATUS_OBJECT_TYPE_MISMATCH:
return "Wrong Type";
case STATUS_OBJECT_NAME_INVALID:
return "Object Name invalid";
case STATUS_OBJECT_NAME_NOT_FOUND:
return "Object Name not found";
case STATUS_SHARING_VIOLATION:
return "Sharing Violation";
case STATUS_INSUFFICIENT_RESOURCES:
return "Insufficient resources";
case STATUS_NOT_SUPPORTED:
return "Operation is not supported";
default:
safe_sprintf(unknown, sizeof(unknown), "Unknown error 0x%08lx", Status);
return unknown;
}
}
/**
* Allocates a block of memory.
*
* \param Size The number of bytes to allocate.
*
* \return A pointer to the allocated block of memory.
*
*/
static PVOID PhAllocate(SIZE_T Size)
{
PF_INIT_OR_OUT(RtlCreateHeap, Ntdll);
PF_INIT_OR_OUT(RtlAllocateHeap, Ntdll);
if (PhHeapHandle == NULL) {
PhHeapHandle = pfRtlCreateHeap(HEAP_GROWABLE, NULL, 2 * MB, 1 * MB, NULL, NULL);
}
return pfRtlAllocateHeap(PhHeapHandle, 0, Size);
out:
return NULL;
}
/**
* Frees a block of memory allocated with PhAllocate().
*
* \param Memory A pointer to a block of memory.
*
*/
static VOID PhFree(PVOID Memory)
{
PF_INIT(RtlFreeHeap, Ntdll);
if (pfRtlFreeHeap != NULL)
pfRtlFreeHeap(PhHeapHandle, 0, Memory);
}
/**
* Enumerates all open handles.
*
* \param Handles A variable which receives a pointer to a structure containing information about
* all opened handles. You must free the structure using PhFree() when you no longer need it.
*
* \return An NTStatus indicating success or the error code.
*/
NTSTATUS PhEnumHandlesEx(PSYSTEM_HANDLE_INFORMATION_EX *Handles)
{
static ULONG initialBufferSize = 0x10000;
NTSTATUS status;
PVOID buffer;
ULONG bufferSize;
PF_INIT(NtQuerySystemInformation, Ntdll);
if (pfNtQuerySystemInformation == NULL)
return STATUS_NOT_IMPLEMENTED;
bufferSize = initialBufferSize;
buffer = PhAllocate(bufferSize);
if (buffer == NULL)
return STATUS_NO_MEMORY;
while ((status = pfNtQuerySystemInformation(SystemExtendedHandleInformation,
buffer, bufferSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) {
PhFree(buffer);
bufferSize *= 2;
// Fail if we're resizing the buffer to something very large.
if (bufferSize > PH_LARGE_BUFFER_SIZE)
return STATUS_INSUFFICIENT_RESOURCES;
buffer = PhAllocate(bufferSize);
if (buffer == NULL)
return STATUS_NO_MEMORY;
}
if (!NT_SUCCESS(status)) {
PhFree(buffer);
return status;
}
if (bufferSize <= 0x200000)
initialBufferSize = bufferSize;
*Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;
return status;
}
/**
* Opens a process.
*
* \param ProcessHandle A variable which receives a handle to the process.
* \param DesiredAccess The desired access to the process.
* \param ProcessId The ID of the process.
*
* \return An NTStatus indicating success or the error code.
*/
NTSTATUS PhOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, HANDLE ProcessId)
{
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
OBJECT_ATTRIBUTES objectAttributes;
CLIENT_ID clientId;
if ((LONG_PTR)ProcessId == (LONG_PTR)GetCurrentProcessId()) {
*ProcessHandle = NtCurrentProcess();
return 0;
}
PF_INIT_OR_OUT(NtOpenProcess, Ntdll);
clientId.UniqueProcess = ProcessId;
clientId.UniqueThread = NULL;
InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
status = pfNtOpenProcess(ProcessHandle, DesiredAccess, &objectAttributes, &clientId);
out:
return status;
}
/**
* Search all the processes and list the ones that have a specific handle open.
*
* \param HandleName The name of the handle to look for.
* \param bPartialMatch Whether partial matches should be allowed.
* \param bIgnoreSelf Whether the current process should be listed.
*
* \return TRUE if matching processes were found, FALSE otherwise.
*/
BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf)
{
NTSTATUS status;
PSYSTEM_HANDLE_INFORMATION_EX handles;
POBJECT_NAME_INFORMATION buffer;
ULONG_PTR i;
ULONG bufferSize;
USHORT wHandleNameLen;
WCHAR *wHandleName;
HANDLE dupHandle = NULL;
HANDLE processHandle = NULL;
BOOLEAN bFound = FALSE;
char exe_path[2][MAX_PATH];
int cur;
status = STATUS_NOT_IMPLEMENTED;
PF_INIT(NtQueryObject, Ntdll);
PF_INIT(NtDuplicateObject, NtDll);
PF_INIT(NtClose, NtDll);
if ((pfNtQueryObject != NULL) && (pfNtClose != NULL) && (pfNtDuplicateObject != NULL))
status = 0;
if (NT_SUCCESS(status))
status = PhEnumHandlesEx(&handles);
if (!NT_SUCCESS(status)) {
uprintf("Could not enumerate handles: %s", NtStatusError(status));
return FALSE;
}
exe_path[0][0] = 0;
cur = 1;
wHandleName = utf8_to_wchar(HandleName);
wHandleNameLen = (USHORT) wcslen(wHandleName);
bufferSize = 0x200;
buffer = PhAllocate(bufferSize);
for (i = 0; ; i++) {
ULONG attempts = 8;
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i];
if ((dupHandle != NULL) && (processHandle != NtCurrentProcess())) {
pfNtClose(dupHandle);
dupHandle = NULL;
}
if (processHandle != NULL) {
if (processHandle != NtCurrentProcess())
pfNtClose(processHandle);
processHandle = NULL;
}
CHECK_FOR_USER_CANCEL;
// Exit loop condition
if (i >= handles->NumberOfHandles)
break;
// Get the process that created the handle we are after
// TODO: We probably should keep a list of the most recent processes and perform a lookup
// instead of Opening the process every time
status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
(HANDLE)handleInfo->UniqueProcessId);
// There exists some processes we can't access
if (!NT_SUCCESS(status))
continue;
// Must duplicate the handle onto our own process, before we can access its properties
if (processHandle == NtCurrentProcess()) {
if (bIgnoreSelf)
continue;
dupHandle = (HANDLE)handleInfo->HandleValue;
} else {
status = pfNtDuplicateObject(processHandle, (HANDLE)handleInfo->HandleValue,
NtCurrentProcess(), &dupHandle, 0, 0, 0);
// Why does it always work for Process Hacker and not me???
if (!NT_SUCCESS(status))
continue;
}
// Filter non-storage handles. We're not interested in them and they make NtQueryObject() freeze
if (GetFileType(dupHandle) != FILE_TYPE_DISK)
continue;
// A loop is needed because the I/O subsystem likes to give us the wrong return lengths...
do {
status = pfNtQueryObject(dupHandle, ObjectBasicInformation + 1,
buffer, bufferSize, &bufferSize);
if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||
status == STATUS_BUFFER_TOO_SMALL) {
PhFree(buffer);
buffer = PhAllocate(bufferSize);
} else {
break;
}
} while (--attempts);
if (!NT_SUCCESS(status))
continue;
// Don't bother comparing if we are looking for full match and the length is different
if ((!bPartialMatch) && (wHandleNameLen != buffer->Name.Length))
continue;
// Likewise, if we are looking for a partial match and the current length is smaller
if ((bPartialMatch) && (wHandleNameLen > buffer->Name.Length))
continue;
// Match against our target string
if (wcsncmp(wHandleName, buffer->Name.Buffer, wHandleNameLen) != 0)
continue;
if (!bFound) {
uprintf("\r\nNOTE: The following process(es) are accessing %s:", HandleName);
bFound = TRUE;
}
// TODO: only list processes with conflicting access rights (ignore "Read attributes" or "Synchronize")
if (GetModuleFileNameExU(processHandle, 0, exe_path[cur], MAX_PATH - 1)) {
// Avoid printing the same path repeatedly
if (strcmp(exe_path[0], exe_path[1]) != 0) {
uprintf("o %s", exe_path[cur]);
cur = (cur + 1) % 2;
}
} else {
uprintf("o Unknown (Process ID %d)", GetProcessId(processHandle));
}
}
out:
if (bFound)
uprintf("You should try to close these applications before attempting to reformat the drive.");
else
uprintf("NOTE: " APPLICATION_NAME " was not able to identify the process(es) preventing access to %s", HandleName);
free(wHandleName);
PhFree(buffer);
return bFound;
}

186
src/search.h Normal file
View File

@ -0,0 +1,186 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Search functionality for handles
*
* Modified from Process Hacker:
* https://github.com/processhacker2/processhacker2/
* Copyright © 2009-2016 wj32
* Copyright © 2017 dmex
* Copyright © 2017 Pete Batard <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <winnt.h>
#include <winternl.h>
#pragma once
#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0x80000001L)
#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
//#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L)
#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS)0xC0000024L)
#define STATUS_OBJECT_NAME_INVALID ((NTSTATUS)0xC0000033L)
#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L)
#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
#define SystemExtendedHandleInformation 64
#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
{
PVOID Object;
ULONG_PTR UniqueProcessId;
ULONG_PTR HandleValue;
ULONG GrantedAccess;
USHORT CreatorBackTraceIndex;
USHORT ObjectTypeIndex;
ULONG HandleAttributes;
ULONG Reserved;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG_PTR NumberOfHandles;
ULONG_PTR Reserved;
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
#if defined(_MSC_VER)
typedef struct _OBJECT_NAME_INFORMATION
{
UNICODE_STRING Name;
} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
typedef struct _CLIENT_ID
{
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
#endif
// Heaps
typedef struct _RTL_HEAP_ENTRY
{
SIZE_T Size;
USHORT Flags;
USHORT AllocatorBackTraceIndex;
union
{
struct
{
SIZE_T Settable;
ULONG Tag;
} s1;
struct
{
SIZE_T CommittedSize;
PVOID FirstBlock;
} s2;
} u;
} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
#define RTL_HEAP_BUSY (USHORT)0x0001
#define RTL_HEAP_SEGMENT (USHORT)0x0002
#define RTL_HEAP_SETTABLE_VALUE (USHORT)0x0010
#define RTL_HEAP_SETTABLE_FLAG1 (USHORT)0x0020
#define RTL_HEAP_SETTABLE_FLAG2 (USHORT)0x0040
#define RTL_HEAP_SETTABLE_FLAG3 (USHORT)0x0080
#define RTL_HEAP_SETTABLE_FLAGS (USHORT)0x00e0
#define RTL_HEAP_UNCOMMITTED_RANGE (USHORT)0x0100
#define RTL_HEAP_PROTECTED_ENTRY (USHORT)0x0200
typedef struct _RTL_HEAP_TAG
{
ULONG NumberOfAllocations;
ULONG NumberOfFrees;
SIZE_T BytesAllocated;
USHORT TagIndex;
USHORT CreatorBackTraceIndex;
WCHAR TagName[24];
} RTL_HEAP_TAG, *PRTL_HEAP_TAG;
typedef struct _RTL_HEAP_INFORMATION
{
PVOID BaseAddress;
ULONG Flags;
USHORT EntryOverhead;
USHORT CreatorBackTraceIndex;
SIZE_T BytesAllocated;
SIZE_T BytesCommitted;
ULONG NumberOfTags;
ULONG NumberOfEntries;
ULONG NumberOfPseudoTags;
ULONG PseudoTagGranularity;
ULONG Reserved[5];
PRTL_HEAP_TAG Tags;
PRTL_HEAP_ENTRY Entries;
} RTL_HEAP_INFORMATION, *PRTL_HEAP_INFORMATION;
typedef struct _RTL_PROCESS_HEAPS
{
ULONG NumberOfHeaps;
RTL_HEAP_INFORMATION Heaps[1];
} RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS;
typedef NTSTATUS(NTAPI *PRTL_HEAP_COMMIT_ROUTINE)(
_In_ PVOID Base,
_Inout_ PVOID *CommitAddress,
_Inout_ PSIZE_T CommitSize
);
#if defined(_MSC_VER)
typedef struct _RTL_HEAP_PARAMETERS
{
ULONG Length;
SIZE_T SegmentReserve;
SIZE_T SegmentCommit;
SIZE_T DeCommitFreeBlockThreshold;
SIZE_T DeCommitTotalFreeThreshold;
SIZE_T MaximumAllocationSize;
SIZE_T VirtualMemoryThreshold;
SIZE_T InitialCommit;
SIZE_T InitialReserve;
PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
SIZE_T Reserved[2];
} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
#endif
#define HEAP_SETTABLE_USER_VALUE 0x00000100
#define HEAP_SETTABLE_USER_FLAG1 0x00000200
#define HEAP_SETTABLE_USER_FLAG2 0x00000400
#define HEAP_SETTABLE_USER_FLAG3 0x00000800
#define HEAP_SETTABLE_USER_FLAGS 0x00000e00
#define HEAP_CLASS_0 0x00000000 // Process heap
#define HEAP_CLASS_1 0x00001000 // Private heap
#define HEAP_CLASS_2 0x00002000 // Kernel heap
#define HEAP_CLASS_3 0x00003000 // GDI heap
#define HEAP_CLASS_4 0x00004000 // User heap
#define HEAP_CLASS_5 0x00005000 // Console heap
#define HEAP_CLASS_6 0x00006000 // User desktop heap
#define HEAP_CLASS_7 0x00007000 // CSR shared heap
#define HEAP_CLASS_8 0x00008000 // CSR port heap
#define HEAP_CLASS_MASK 0x0000f000

View File

@ -717,19 +717,19 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// We need an IGroupPolicyObject instance to set a Local Group Policy
hr = CoCreateInstance(&my_CLSID_GroupPolicyObject, NULL, CLSCTX_INPROC_SERVER, &my_IID_IGroupPolicyObject, (LPVOID*)&pLGPO);
if (FAILED(hr)) {
ubprintf("SetLGP: CoCreateInstance failed; hr = %x", hr);
ubprintf("SetLGP: CoCreateInstance failed; hr = %lx", hr);
goto error;
}
hr = pLGPO->lpVtbl->OpenLocalMachineGPO(pLGPO, GPO_OPEN_LOAD_REGISTRY);
if (FAILED(hr)) {
ubprintf("SetLGP: OpenLocalMachineGPO failed - error %x", hr);
ubprintf("SetLGP: OpenLocalMachineGPO failed - error %lx", hr);
goto error;
}
hr = pLGPO->lpVtbl->GetRegistryKey(pLGPO, GPO_SECTION_MACHINE, &path_key);
if (FAILED(hr)) {
ubprintf("SetLGP: GetRegistryKey failed - error %x", hr);
ubprintf("SetLGP: GetRegistryKey failed - error %lx", hr);
goto error;
}
@ -737,7 +737,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
r = RegCreateKeyExA(path_key, p->szPath, 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE,
NULL, &policy_key, &disp);
if (r != ERROR_SUCCESS) {
ubprintf("SetLGP: Failed to open LGPO path %s - error %x", p->szPath, hr);
ubprintf("SetLGP: Failed to open LGPO path %s - error %lx", p->szPath, hr);
policy_key = NULL;
goto error;
}
@ -751,7 +751,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// The Key exists but not its value, which is OK
*(p->bExistingKey) = FALSE;
} else if (r != ERROR_SUCCESS) {
ubprintf("SetLGP: Failed to read original %s policy value - error %x", p->szPolicy, r);
ubprintf("SetLGP: Failed to read original %s policy value - error %lx", p->szPolicy, r);
}
}
@ -762,7 +762,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
r = RegDeleteValueA(policy_key, p->szPolicy);
}
if (r != ERROR_SUCCESS) {
ubprintf("SetLGP: RegSetValueEx / RegDeleteValue failed - error %x", r);
ubprintf("SetLGP: RegSetValueEx / RegDeleteValue failed - error %lx", r);
}
RegCloseKey(policy_key);
policy_key = NULL;
@ -770,11 +770,11 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// Apply policy
hr = pLGPO->lpVtbl->Save(pLGPO, TRUE, (p->bRestore)?FALSE:TRUE, &ext_guid, &snap_guid);
if (hr != S_OK) {
ubprintf("SetLGP: Unable to apply %s policy - error %x", p->szPolicy, hr);
ubprintf("SetLGP: Unable to apply %s policy - error %lx", p->szPolicy, hr);
goto error;
} else {
if ((!p->bRestore) || (*(p->bExistingKey))) {
ubprintf("SetLGP: Successfully %s %s policy to 0x%08X", (p->bRestore)?"restored":"set", p->szPolicy, val);
ubprintf("SetLGP: Successfully %s %s policy to 0x%08lX", (p->bRestore)?"restored":"set", p->szPolicy, val);
} else {
ubprintf("SetLGP: Successfully removed %s policy key", p->szPolicy);
}

View File

@ -1855,7 +1855,7 @@ void ClrFormatPromptHook(void) {
}
#ifdef RUFUS_TEST
static inline LPWORD lpwAlign(LPWORD addr)
static __inline LPWORD lpwAlign(LPWORD addr)
{
return (LPWORD)((((uintptr_t)addr) + 3) & (~3));
}