diff --git a/ctypes_generation/definitions/winstruct.txt b/ctypes_generation/definitions/winstruct.txt index 66bb92d..06366b5 100644 --- a/ctypes_generation/definitions/winstruct.txt +++ b/ctypes_generation/definitions/winstruct.txt @@ -2110,12 +2110,14 @@ typedef struct _WINTRUST_DATA } WINTRUST_DATA, *PWINTRUST_DATA; -typedef struct _PROCESS_BASIC_INFORMATION { - PVOID Reserved1; +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; PPEB PebBaseAddress; - PVOID Reserved2[2]; - ULONG_PTR UniqueProcessId; - PVOID Reserved3; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; typedef struct _JIT_DEBUG_INFO { diff --git a/ctypes_generation/generate.py b/ctypes_generation/generate.py index 3c78327..3786fba 100644 --- a/ctypes_generation/generate.py +++ b/ctypes_generation/generate.py @@ -37,6 +37,7 @@ TYPE_EQUIVALENCE = [ ('PHANDLER_ROUTINE', 'PVOID'), ('LPBYTE', 'POINTER(BYTE)'), ('ULONG_PTR','PVOID'), + ('DWORD_PTR','ULONG_PTR'), ('KAFFINITY','ULONG_PTR'), ('KPRIORITY','LONG'), ('CHAR', 'c_char'), @@ -95,6 +96,7 @@ TYPE_EQUIVALENCE = [ ("DISPID", "LONG"), ("MEMBERID", "DISPID"), ('PSECURITY_DESCRIPTOR', 'PVOID'), + ('LPPROC_THREAD_ATTRIBUTE_LIST', 'PVOID'), ('LPUNKNOWN', 'POINTER(PVOID)'), ('SPC_UUID', 'BYTE * 16'), #STUFF FOR COM (will be replace at runtime diff --git a/windows/generated_def/winstructs.py b/windows/generated_def/winstructs.py index 1302c8b..6bbd658 100644 --- a/windows/generated_def/winstructs.py +++ b/windows/generated_def/winstructs.py @@ -22,6 +22,7 @@ WNDENUMPROC = PVOID PHANDLER_ROUTINE = PVOID LPBYTE = POINTER(BYTE) ULONG_PTR = PVOID +DWORD_PTR = ULONG_PTR KAFFINITY = ULONG_PTR KPRIORITY = LONG CHAR = c_char @@ -79,6 +80,7 @@ ALG_ID = UINT DISPID = LONG MEMBERID = DISPID PSECURITY_DESCRIPTOR = PVOID +LPPROC_THREAD_ATTRIBUTE_LIST = PVOID LPUNKNOWN = POINTER(PVOID) SPC_UUID = BYTE * 16 PWINDBG_EXTENSION_APIS32 = PVOID @@ -2715,6 +2717,18 @@ class _PROCESS_BASIC_INFORMATION(Structure): PPROCESS_BASIC_INFORMATION = POINTER(_PROCESS_BASIC_INFORMATION) PROCESS_BASIC_INFORMATION = _PROCESS_BASIC_INFORMATION +class _PROCESS_BASIC_INFORMATION(Structure): + _fields_ = [ + ("ExitStatus", NTSTATUS), + ("PebBaseAddress", PPEB), + ("AffinityMask", ULONG_PTR), + ("BasePriority", KPRIORITY), + ("UniqueProcessId", HANDLE), + ("InheritedFromUniqueProcessId", HANDLE), + ] +PPROCESS_BASIC_INFORMATION = POINTER(_PROCESS_BASIC_INFORMATION) +PROCESS_BASIC_INFORMATION = _PROCESS_BASIC_INFORMATION + class _JIT_DEBUG_INFO(Structure): _fields_ = [ ("dwSize", DWORD), diff --git a/windows/test/mytest.py b/windows/test/mytest.py index 4cff65a..59e8904 100644 --- a/windows/test/mytest.py +++ b/windows/test/mytest.py @@ -61,6 +61,22 @@ class WindowsTestCase(unittest.TestCase): with Calc64() as calc: self.assertEqual(calc.bitness, 64) + @check_for_gc_garbage + def test_current_process_ppid(self): + myself = [p for p in windows.system.processes if p.pid == windows.current_process.pid][0] + self.assertEqual(myself.ppid, windows.current_process.ppid) + + @check_for_gc_garbage + def test_process_ppid_32(self): + with Calc32() as calc: + self.assertEqual(calc.ppid, windows.current_process.pid) + + @windows_64bit_only + @check_for_gc_garbage + def test_process_ppid_64(self): + with Calc64() as calc: + self.assertEqual(calc.ppid, windows.current_process.pid) + @check_for_gc_garbage def test_get_current_process_peb(self): return windows.current_process.peb diff --git a/windows/winobject/process.py b/windows/winobject/process.py index 4acd54d..0e9c0c3 100644 --- a/windows/winobject/process.py +++ b/windows/winobject/process.py @@ -340,6 +340,26 @@ class Process(AutoHandle): return 32 return 64 + + @utils.fixedpropety + def ppid(self): + """Parent Process ID + + :type: :class:`int` + """ + if windows.current_process.bitness == 32 and self.bitness == 64: + xtype = windows.remotectypes.transform_type_to_remote64bits(PROCESS_BASIC_INFORMATION) + # Fuck-it <3 + data = (ctypes.c_char * ctypes.sizeof(xtype))() + windows.syswow64.NtQueryInformationProcess_32_to_64(self.handle, ProcessInformation=data, ProcessInformationLength=ctypes.sizeof(xtype)) + # Map a remote64bits(PROCESS_BASIC_INFORMATION) at the address of 'data' + x = xtype(ctypes.addressof(data), windows.current_process) + else: + information_type = 0 + x = PROCESS_BASIC_INFORMATION() + winproxy.NtQueryInformationProcess(self.handle, information_type, x) + return x.InheritedFromUniqueProcessId + @property def threads(self): """The threads of the process @@ -747,15 +767,6 @@ class CurrentProcess(Process): """ return os.getpid() - # Is there a better way ? - @utils.fixedpropety - def ppid(self): - """Parent Process ID - - :type: :class:`int` - """ - return [p for p in windows.system.processes if p.pid == self.pid][0].ppid - @utils.fixedpropety # leave it has fixed property as we don't care if CurrentProcess is never collected def peb(self): """The Process Environment Block of the current process @@ -883,16 +894,6 @@ class WinProcess(Process): """ return winproxy.GetProcessId(self.handle) - @utils.fixedpropety - def ppid(self): - """Parent Process ID - - :type: :class:`int` - """ - # TODO: is there an API ? - pid = self.pid - return [p for p in windows.system.processes if p.pid == pid][0].th32ParentProcessID - def _get_handle(self): return winproxy.OpenProcess(dwProcessId=self.pid)