diff --git a/src/.clang/rufus.vcxproj b/src/.clang/rufus.vcxproj index aab1308d..871e78a4 100644 --- a/src/.clang/rufus.vcxproj +++ b/src/.clang/rufus.vcxproj @@ -210,6 +210,7 @@ + @@ -225,6 +226,7 @@ + diff --git a/src/.clang/rufus.vcxproj.filters b/src/.clang/rufus.vcxproj.filters index 45f75f62..a2a22b5c 100644 --- a/src/.clang/rufus.vcxproj.filters +++ b/src/.clang/rufus.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + @@ -143,6 +146,9 @@ Header Files + + Header Files + diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj index cdf0851c..5ace4593 100644 --- a/src/.msvc/rufus.vcxproj +++ b/src/.msvc/rufus.vcxproj @@ -193,6 +193,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters index 45f75f62..a2a22b5c 100644 --- a/src/.msvc/rufus.vcxproj.filters +++ b/src/.msvc/rufus.vcxproj.filters @@ -75,6 +75,9 @@ Source Files + + Source Files + @@ -143,6 +146,9 @@ Header Files + + Header Files + diff --git a/src/Makefile.am b/src/Makefile.am index a46a084c..fd26d668 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/Makefile.in b/src/Makefile.in index c306667e..abee2dd9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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 diff --git a/src/drive.c b/src/drive.c index d072f01d..6105c3d9 100644 --- a/src/drive.c +++ b/src/drive.c @@ -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); } diff --git a/src/license.h b/src/license.h index 0fdc08d3..dfc83094 100644 --- a/src/license.h +++ b/src/license.h @@ -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" diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h index 7317def4..9f71a5ff 100644 --- a/src/msapi_utf8.h +++ b/src/msapi_utf8.h @@ -31,6 +31,9 @@ #include #include #include +#if !defined(DDKBUILD) +#include +#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; diff --git a/src/rufus.c b/src/rufus.c index 84c3fe37..ec908f85 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -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 diff --git a/src/rufus.h b/src/rufus.h index e9cce68c..c9e548ff 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -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); diff --git a/src/rufus.rc b/src/rufus.rc index 01d89e23..ebd26728 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -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" diff --git a/src/search.c b/src/search.c new file mode 100644 index 00000000..421166b2 --- /dev/null +++ b/src/search.c @@ -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 + * + * 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 . + */ + +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#endif + +#include + +#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; +} diff --git a/src/search.h b/src/search.h new file mode 100644 index 00000000..92cd8841 --- /dev/null +++ b/src/search.h @@ -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 + * + * 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 . + */ + +#include +#include +#include + +#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 diff --git a/src/stdfn.c b/src/stdfn.c index 6f3231e3..579571c6 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -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); } diff --git a/src/stdlg.c b/src/stdlg.c index 51f0c232..21cd322d 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -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)); }