Last active
May 9, 2024 07:10
-
-
Save Pagliacii/774ed5d3ea78a36cdb0754be6a25408d to your computer and use it in GitHub Desktop.
Use ctypes to call WIndows API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# _*_ coding:utf-8 _*_ | |
import ctypes | |
import os | |
from ctypes import windll, wintypes | |
from typing import Optional | |
NULL: int = 0 | |
GENERIC_ALL: int = 28 | |
GENERIC_EXECUTE: int = 29 | |
GENERIC_WRITE: int = 30 | |
GENERIC_READ: int = 31 | |
FILE_SHARE_DISABLE: int = 0x00000000 | |
FILE_SHARE_READ: int = 0x00000001 | |
FILE_SHARE_WRITE: int = 0x00000002 | |
FILE_SHARE_DELETE: int = 0x00000004 | |
CREATE_NEW: int = 1 | |
CREATE_ALWAYS: int = 2 | |
OPEN_EXISTING: int = 3 | |
OPEN_ALWAYS: int = 4 | |
TRUNCATE_EXISTING: int = 5 | |
FILE_ATTRIBUTE_READONLY: int = 0x1 | |
FILE_ATTRIBUTE_HIDDEN: int = 0x2 | |
FILE_ATTRIBUTE_SYSTEM: int = 0x4 | |
FILE_ATTRIBUTE_DIRECTORY: int = 0x10 | |
FILE_ATTRIBUTE_ARCHIVE: int = 0x20 | |
FILE_ATTRIBUTE_DEVICE: int = 0x40 | |
FILE_ATTRIBUTE_NORMAL: int = 0x80 | |
FILE_ATTRIBUTE_TEMPORARY: int = 0x100 | |
FILE_ATTRIBUTE_SPARSE_FILE: int = 0x200 | |
FILE_ATTRIBUTE_REPARSE_POINT: int = 0x400 | |
FILE_ATTRIBUTE_COMPRESSED: int = 0x800 | |
FILE_ATTRIBUTE_OFFLINE: int = 0x1000 | |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED: int = 0x2000 | |
FILE_ATTRIBUTE_ENCRYPTED: int = 0x4000 | |
FILE_ATTRIBUTE_INTEGRITY_STREAM: int = 0x8000 | |
FILE_ATTRIBUTE_VIRTUAL: int = 0x10000 | |
FILE_ATTRIBUTE_NO_SCRUB_DATA: int = 0x20000 | |
FILE_ATTRIBUTE_RECALL_ON_OPEN: int = 0x40000 | |
FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS: int = 0x400000 | |
FILE_FLAG_BACKUP_SEMANTICS: int = 0x02000000 | |
FILE_FLAG_DELETE_ON_CLOSE: int = 0x04000000 | |
FILE_FLAG_NO_BUFFERING: int = 0x20000000 | |
FILE_FLAG_OPEN_NO_RECALL: int = 0x00100000 | |
FILE_FLAG_OPEN_REPARSE_POINT: int = 0x00200000 | |
FILE_FLAG_OVERLAPPED: int = 0x40000000 | |
FILE_FLAG_POSIX_SEMANTICS: int = 0x0100000 | |
FILE_FLAG_RANDOM_ACCESS: int = 0x10000000 | |
FILE_FLAG_SESSION_AWARE: int = 0x00800000 | |
FILE_FLAG_SEQUENTIAL_SCAN: int = 0x08000000 | |
FILE_FLAG_WRITE_THROUGH: int = 0x80000000 | |
# ref: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa379560(v=vs.85) | |
class SECURITY_ATTRIBUTES(ctypes.Structure): | |
_fields_ = [ | |
("nLength", wintypes.DWORD), | |
("lpSecurityDescriptor", wintypes.LPVOID), | |
("bInheritHandle", wintypes.BOOL) | |
] | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-large_integer-r1 | |
class LARGE_INTEGER(ctypes.Structure): | |
_fields_ = [ | |
("QuadPart", ctypes.c_longlong) | |
] | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew | |
def create_file( | |
path: str, | |
access: int=GENERIC_READ, | |
share_mode: int=FILE_SHARE_DISABLE, | |
security_attrs: Optional[SECURITY_ATTRIBUTES]=None, | |
creation: int=OPEN_EXISTING, | |
flags: int=FILE_ATTRIBUTE_NORMAL, | |
template: Optional[wintypes.HANDLE]=None, | |
) -> wintypes.HANDLE: | |
CreateFileW = windll.kernel32.CreateFileW | |
CreateFileW.argtypes = ( | |
wintypes.LPCWSTR, # LPCWSTR lpFileName | |
wintypes.DWORD, # DWORD dwDesiredAccess | |
wintypes.DWORD, # DWORD dwShareMode | |
wintypes.LPVOID, # LPSECURITY_ATTRIBUTES lpSecurityAttributes | |
wintypes.DWORD, # DWORD dwCreationDisposition | |
wintypes.DWORD, # DWORD dwFlagsAndAttributes | |
wintypes.HANDLE, # HANDLE hTemplateFile | |
) | |
CreateFileW.restype = wintypes.HANDLE | |
# these two arguments below have not been testing. | |
lpSecurityAttributes = ctypes.byref(security_attrs) if security_attrs else NULL | |
hTemplateFile = template if template else NULL | |
return CreateFileW( | |
path, access, share_mode, lpSecurityAttributes, | |
creation, flags, hTemplateFile | |
) | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfilesizeex | |
def get_file_size(path: str) -> int: | |
GetFileSizeEx = windll.kernel32.GetFileSizeEx | |
GetFileSizeEx.argtypes = ( | |
wintypes.HANDLE, # HANDLE hFile | |
ctypes.POINTER(LARGE_INTEGER), # PLARGE_INTEGER lpFileSize | |
) | |
GetFileSizeEx.restype = wintypes.BOOL | |
size = LARGE_INTEGER(0) | |
handle = create_file(path) | |
result = GetFileSizeEx(handle, ctypes.byref(size)) | |
close_handle(handle) | |
if not result: | |
raise ctypes.WinError() | |
return size.QuadPart | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw | |
def get_temp_path(max_size: Optional[int]=None) -> str: | |
GetTempPathW = windll.kernel32.GetTempPathW | |
GetTempPathW.argtypes = ( | |
wintypes.DWORD, # DWORD nBufferLength | |
wintypes.LPWSTR, # LPWSTR lpBuffer | |
) | |
GetTempPathW.restype = wintypes.DWORD # zero for failure | |
if not max_size: | |
max_size = wintypes.MAX_PATH | |
buffer = ctypes.create_unicode_buffer(max_size) | |
lpBuffer = ctypes.cast(ctypes.byref(buffer), wintypes.LPWSTR) | |
result = GetTempPathW(max_size, lpBuffer) | |
if result == 0: | |
raise ctypes.WinError() | |
return buffer.value.rstrip() | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamew | |
def get_temp_file_name( | |
parent_path: str=".", | |
prefix: Optional[str]=None, | |
unique: Optional[int]=0 | |
) -> str: | |
GetTempFileNameW = windll.kernel32.GetTempFileNameW | |
GetTempFileNameW.argtypes = ( | |
wintypes.LPCWSTR, # LPCWSTR lpPathName | |
wintypes.LPCWSTR, # LPCWSTR lpPrefixString | |
wintypes.UINT, # UINT uUnique | |
wintypes.LPWSTR, # LPWSTR lpTempFileName | |
) | |
GetTempFileNameW.restype = wintypes.UINT # zero for failure | |
buffer = ctypes.create_unicode_buffer(wintypes.MAX_PATH) | |
lpTempFileName = ctypes.cast(ctypes.byref(buffer), wintypes.LPWSTR) | |
result = GetTempFileNameW(parent_path, prefix, unique, lpTempFileName) | |
if result == 0: | |
raise ctypes.WinError() | |
return buffer.value.rstrip() | |
# ref: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle | |
def close_handle(handle: wintypes.HANDLE) -> bool: | |
CloseHandle = windll.kernel32.CloseHandle | |
CloseHandle.argtypes = (wintypes.HANDLE,) | |
CloseHandle.restype = wintypes.BOOL | |
result = CloseHandle(handle) | |
if not result: | |
raise ctypes.WinError() | |
return True | |
def print_file_size(path: str) -> None: | |
print(f"The size of {path}:") | |
print(f"\tvia ctypes module: {get_file_size(path)}") | |
print(f"\tvia os module: {os.path.getsize(path)}") | |
print() | |
def main(): | |
import tempfile | |
temp_dir: str = get_temp_path() | |
temp_file: str = get_temp_file_name(temp_dir, prefix="win") | |
path = os.path.abspath(temp_file) | |
with open(path, "wb") as f: | |
f.write(os.urandom(1024)) | |
print("File generated by Win32 API.") | |
print_file_size(path) | |
temp_dir: str = tempfile.gettempdir() | |
file_descriptor: int | |
path: str | |
file_descriptor, path = tempfile.mkstemp(prefix="tempfile", dir=temp_dir) | |
with os.fdopen(file_descriptor, mode="wb") as f: | |
f.write(os.urandom(1024)) | |
print("File generated by Python tempfile module.") | |
print_file_size(path) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment