Форум сайта python.su
31
Используя winapi, пытаюсь обнаружить процесс блокирующий файл
На примере handle.exe, нашел похожий функционал написанный на python, ниже, но почему то работает не так как, допустим здесь http://www.codeproject.com/Articles/18975/Listing-Used-Files
в принципе, код находит процессы, пусть не все, которые пользуют файлы, но находит
В общем, не хотелось бы использовать стороннее ПО, типа handle, а доработать код если это возможно
import os import struct import winerror import win32file import win32con from ctypes import * from ctypes.wintypes import * from Queue import Queue from threading import Thread from win32api import GetCurrentProcess, OpenProcess, DuplicateHandle from win32api import error as ApiError from win32con import ( FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_SIZE, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_NOTIFY_CHANGE_SECURITY, DUPLICATE_SAME_ACCESS ) from win32event import WaitForSingleObject, WAIT_TIMEOUT, WAIT_ABANDONED from win32event import error as EventError from win32file import CreateFile, ReadDirectoryChangesW, CloseHandle from win32file import error as FileError # from ubuntuone.platform.windows.os_helper import LONG_PATH_PREFIX, abspath LONG_PATH_PREFIX = '\\\\?\\' # constant found in the msdn documentation: # http://msdn.microsoft.com/en-us/library/ff538834(v=vs.85).aspx FILE_LIST_DIRECTORY = 0x0001 FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020 FILE_NOTIFY_CHANGE_CREATION = 0x00000040 # XXX: the following code is some kind of hack that allows to get the opened # files in a system. The techinique uses an no documented API from windows nt # that is internal to MS and might change in the future braking our code :( UCHAR = c_ubyte PVOID = c_void_p ntdll = windll.ntdll SystemHandleInformation = 16 STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 STATUS_BUFFER_OVERFLOW = 0x80000005L STATUS_INVALID_HANDLE = 0xC0000008L STATUS_BUFFER_TOO_SMALL = 0xC0000023L STATUS_SUCCESS = 0 CURRENT_PROCESS = GetCurrentProcess () DEVICE_DRIVES = {} for d in "abcdefghijklmnopqrstuvwxyz": try: DEVICE_DRIVES[win32file.QueryDosDevice (d + ":").strip ("\x00").lower ()] = d + ":" except FileError, (errno, errctx, errmsg): if errno == 2: pass else: raise class x_file_handles(Exception): pass def signed_to_unsigned(signed): unsigned, = struct.unpack ("L", struct.pack ("l", signed)) return unsigned class SYSTEM_HANDLE_TABLE_ENTRY_INFO(Structure): """Represent the SYSTEM_HANDLE_TABLE_ENTRY_INFO on ntdll.""" _fields_ = [ ("UniqueProcessId", USHORT), ("CreatorBackTraceIndex", USHORT), ("ObjectTypeIndex", UCHAR), ("HandleAttributes", UCHAR), ("HandleValue", USHORT), ("Object", PVOID), ("GrantedAccess", ULONG), ] class SYSTEM_HANDLE_INFORMATION(Structure): """Represent the SYSTEM_HANDLE_INFORMATION on ntdll.""" _fields_ = [ ("NumberOfHandles", ULONG), ("Handles", SYSTEM_HANDLE_TABLE_ENTRY_INFO * 1), ] class LSA_UNICODE_STRING(Structure): """Represent the LSA_UNICODE_STRING on ntdll.""" _fields_ = [ ("Length", USHORT), ("MaximumLength", USHORT), ("Buffer", LPWSTR), ] class PUBLIC_OBJECT_TYPE_INFORMATION(Structure): """Represent the PUBLIC_OBJECT_TYPE_INFORMATION on ntdll.""" _fields_ = [ ("Name", LSA_UNICODE_STRING), ("Reserved", ULONG * 22), ] class OBJECT_NAME_INFORMATION (Structure): """Represent the OBJECT_NAME_INFORMATION on ntdll.""" _fields_ = [ ("Name", LSA_UNICODE_STRING), ] class IO_STATUS_BLOCK_UNION (Union): """Represent the IO_STATUS_BLOCK_UNION on ntdll.""" _fields_ = [ ("Status", LONG), ("Pointer", PVOID), ] class IO_STATUS_BLOCK (Structure): """Represent the IO_STATUS_BLOCK on ntdll.""" _anonymous_ = ("u",) _fields_ = [ ("u", IO_STATUS_BLOCK_UNION), ("Information", POINTER (ULONG)), ] class FILE_NAME_INFORMATION (Structure): """Represent the on FILE_NAME_INFORMATION ntdll.""" filename_size = 4096 _fields_ = [ ("FilenameLength", ULONG), ("FileName", WCHAR * filename_size), ] def get_handles(): """Return all the processes handles in the system atm.""" system_handle_information = SYSTEM_HANDLE_INFORMATION() size = DWORD (sizeof (system_handle_information)) while True: result = ntdll.NtQuerySystemInformation( SystemHandleInformation, byref(system_handle_information), size, byref(size) ) result = signed_to_unsigned(result) if result == STATUS_SUCCESS: break elif result == STATUS_INFO_LENGTH_MISMATCH: size = DWORD(size.value * 4) resize(system_handle_information, size.value) else: raise x_file_handles("NtQuerySystemInformation", hex(result)) pHandles = cast( system_handle_information.Handles, POINTER(SYSTEM_HANDLE_TABLE_ENTRY_INFO * \ system_handle_information.NumberOfHandles) ) for handle in pHandles.contents: yield handle.UniqueProcessId, handle.HandleValue def get_process_handle (pid, handle): """Get a handle for the process with the given pid.""" try: hProcess = OpenProcess(win32con.PROCESS_DUP_HANDLE, 0, pid) return DuplicateHandle(hProcess, handle, CURRENT_PROCESS, 0, 0, DUPLICATE_SAME_ACCESS) except ApiError,(errno, errctx, errmsg): if errno in ( winerror.ERROR_ACCESS_DENIED, winerror.ERROR_INVALID_PARAMETER, winerror.ERROR_INVALID_HANDLE, winerror.ERROR_NOT_SUPPORTED ): return None else: raise def get_type_info (handle): """Get the handle type information.""" public_object_type_information = PUBLIC_OBJECT_TYPE_INFORMATION() size = DWORD(sizeof(public_object_type_information)) while True: result = signed_to_unsigned( ntdll.NtQueryObject( handle, 2, byref(public_object_type_information), size, None)) if result == STATUS_SUCCESS: return public_object_type_information.Name.Buffer elif result == STATUS_INFO_LENGTH_MISMATCH: size = DWORD(size.value * 4) resize(public_object_type_information, size.value) elif result == STATUS_INVALID_HANDLE: return None else: raise x_file_handles("NtQueryObject.2", hex (result)) def get_name_info (handle): """Get the handle name information.""" object_name_information = OBJECT_NAME_INFORMATION() size = DWORD(sizeof(object_name_information)) while True: result = signed_to_unsigned( ntdll.NtQueryObject(handle, 1, byref (object_name_information), size, None)) if result == STATUS_SUCCESS: return object_name_information.Name.Buffer elif result in (STATUS_BUFFER_OVERFLOW, STATUS_BUFFER_TOO_SMALL, STATUS_INFO_LENGTH_MISMATCH): size = DWORD(size.value * 4) resize (object_name_information, size.value) else: return None def filepath_from_devicepath (devicepath): """Return a file path from a device path.""" if devicepath is None: return None devicepath = devicepath.lower() for device, drive in DEVICE_DRIVES.items(): if devicepath.startswith(device): return drive + devicepath[len(device):] else: return devicepath def get_real_path(path): """Return the real path avoiding issues with the Library a in Windows 7""" assert os.path.isdir(path) handle = CreateFile( path, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, None ) name = get_name_info(int(handle)) CloseHandle(handle) return filepath_from_devicepath(name) def get_open_file_handles(): """Return all the open file handles.""" print 'get_open_file_handles' result = set() this_pid = os.getpid() for pid, handle in get_handles(): if pid == this_pid: continue duplicate = get_process_handle(pid, handle) if duplicate is None: continue else: # get the type info and name info of the handle type = get_type_info(handle) name = get_name_info(handle) # add the handle to the result only if it is a file if type and type == 'File': # the name info represents the path to the object, # we need to convert it to a file path and then # test that it does exist if name: file_path = filepath_from_devicepath(name) if os.path.exists(file_path): result.add(file_path) return result def get_open_file_handles_under_directory(directory): """get the open files under a directory.""" result = set() all_handles = get_open_file_handles() #print all_handles # to avoid issues with Libraries on Windows 7 and later, we will # have to get the real path directory = get_real_path(os.path.abspath(directory)) print 'Dir ' + directory if not directory.endswith(os.path.sep): directory += os.path.sep for file in all_handles: print 'Current file ' + file if directory in file: result.add(file) return result Dir = os.environ["USERPROFILE"] direct = Dir + "\AppData\Local\Temp" get_open_file_handles_under_directory(direct)
Отредактировано sanodin (Янв. 24, 2014 20:43:35)
Офлайн
31
Показывает DLL используемые процессом, но не файлы и не все процессы
from ctypes import byref, create_unicode_buffer, sizeof, WinDLL from ctypes.wintypes import DWORD, HMODULE, MAX_PATH Psapi = WinDLL('Psapi.dll') Kernel32 = WinDLL('kernel32.dll') PROCESS_QUERY_INFORMATION = 0x0400 PROCESS_VM_READ = 0x0010 LIST_MODULES_ALL = 0x03 def EnumProcesses(): buf_count = 256 while True: buf = (DWORD * buf_count)() buf_size = sizeof(buf) res_size = DWORD() if not Psapi.EnumProcesses(byref(buf), buf_size, byref(res_size)): raise OSError('EnumProcesses failed') if res_size.value >= buf_size: buf_count *= 2 continue count = res_size.value // (buf_size // buf_count) return buf[:count] def EnumProcessModulesEx(hProcess): buf_count = 256 while True: buf = (HMODULE * buf_count)() buf_size = sizeof(buf) needed = DWORD() if not Psapi.EnumProcessModulesEx(hProcess, byref(buf), buf_size, byref(needed), LIST_MODULES_ALL): raise OSError('EnumProcessModulesEx failed') if buf_size < needed.value: buf_count = needed.value // (buf_size // buf_count) continue count = needed.value // (buf_size // buf_count) return map(HMODULE, buf[:count]) def GetModuleFileNameEx(hProcess, hModule): buf = create_unicode_buffer(MAX_PATH) nSize = DWORD() if not Psapi.GetModuleFileNameExW(hProcess, hModule, byref(buf), byref(nSize)): raise OSError('GetModuleFileNameEx failed') return buf.value def get_process_modules(pid): hProcess = Kernel32.OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, pid) if not hProcess: raise OSError('Could not open PID %s' % pid) try: return [ GetModuleFileNameEx(hProcess, hModule) for hModule in EnumProcessModulesEx(hProcess)] finally: Kernel32.CloseHandle(hProcess) for pid in EnumProcesses(): try: dll_list = get_process_modules(pid) print('dll_list: ', dll_list) except OSError as ose: print(str(ose)) print('-' * 14)
-------------- Could not open PID 1636 -------------- ('dll_list: ', [u'C:\\Python27\\pythonw.exe', u'C:\\Windows\\SYSTEM32\\ntdll.dll', u'C:\\Windows\\system32\\kernel32.dll', u'C:\\Windows\\system32\\KERNELBASE.dll', u'C:\\Windows\\system32\\python27.dll', u'C:\\Windows\\system32\\USER32.dll', u'C:\\Windows\\system32\\GDI32.dll', u'C:\\Windows\\system32\\LPK.dll', u'C:\\Windows\\system32\\USP10.dll', u'C:\\Windows\\system32\\msvcrt.dll', u'C:\\Windows\\system32\\ADVAPI32.dll', u'C:\\Windows\\SYSTEM32\\sechost.dll', u'C:\\Windows\\system32\\RPCRT4.dll', u'C:\\Windows\\system32\\SHELL32.dll', u'C:\\Windows\\system32\\SHLWAPI.dll', u'C:\\Windows\\WinSxS\\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.6161_none_50934f2ebcb7eb57\\MSVCR90.dll', u'C:\\Windows\\system32\\IMM32.DLL', u'C:\\Windows\\system32\\MSCTF.dll', u'C:\\Python27\\DLLs\\_socket.pyd', u'C:\\Windows\\system32\\WS2_32.dll', u'C:\\Windows\\system32\\NSI.dll', u'C:\\Python27\\DLLs\\_ssl.pyd', u'C:\\Python27\\DLLs\\_ctypes.pyd', u'C:\\Windows\\system32\\ole32.dll', u'C:\\Windows\\system32\\OLEAUT32.dll', u'C:\\Python27\\DLLs\\_tkinter.pyd', u'C:\\Python27\\DLLs\\tcl85.dll', u'C:\\Python27\\DLLs\\tk85.dll', u'C:\\Windows\\system32\\COMDLG32.dll', u'C:\\Windows\\WinSxS\\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.7601.17514_none_ec83dffa859149af\\COMCTL32.dll', u'C:\\Python27\\DLLs\\select.pyd', u'C:\\Python27\\DLLs\\_hashlib.pyd', u'C:\\Windows\\system32\\CRYPTSP.dll', u'C:\\Windows\\system32\\rsaenh.dll', u'C:\\Windows\\system32\\CRYPTBASE.dll', u'C:\\Windows\\system32\\mswsock.dll', u'C:\\Windows\\System32\\wshtcpip.dll', u'C:\\Windows\\system32\\Psapi.dll']) --------------
Офлайн