Python3 从 PID 获取进程基地址

Python3 get process base-address from PID

我正在尝试获取 Windows(64 位)进程的基址,使用 Python3,假设知道 PID。 我查看了堆栈上的所有问题,但解决方案 old/not 有效。

我假设在名为 pid 的变量中包含进程的 PID。

我尝试过的众多代码之一是

PROCESS_ALL_ACCESS = 0x1F0FFF
processHandle = win32api.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
modules = win32process.EnumProcessModules(processHandle)
fileName = win32process.GetModuleFileNameEx(processHandle, modules[0])
base_address = win32api.GetModuleHandle(fileName)
processHandle.close()

但是我在 GetModuleHandle 上遇到错误:'Impossible to find the specified module'。

感谢您的帮助。

根据[MS.Docs]: GetModuleHandleW function重点是我的):

Retrieves a module handle for the specified module. The module must have been loaded by the calling process.

这意味着它对当前进程可以正常工作,但对于任何其他进程你会得到 未定义的行为,因为你尝试检索:

  1. 来自其他进程的.dll(或.exe)名称(GetModuleFileNameEx呼叫)
  2. 名称在上一步(GetModuleHandle 调用)的句柄但在当前进程中(如果加载),这使得没有意义

虽然没有关于这个主题的明确文档(或者至少我找不到任何文档),句柄 的基础地址。这是你也依赖的一个原则(调用GetModuleHandle),但是你可以直接使用EnumProcessModules返回的值(看下面的例子, 值相同)。

如果要严谨,可以用[MS.Docs]: GetModuleInformation function. Unfortunately, that's not exported by PyWin32, and an alternative is using [Python 3.Docs]: ctypes - A foreign function library for Python

code00.py:

#!/usr/bin/env python3

import sys
import win32api as wapi
import win32process as wproc
import win32con as wcon
import ctypes as ct
from ctypes import wintypes as wt
import traceback as tb


class MODULEINFO(ct.Structure):
    _fields_ = [
        ("lpBaseOfDll", ct.c_void_p),
        ("SizeOfImage", wt.DWORD),
        ("EntryPoint", ct.c_void_p),
    ]

get_module_information_func_name = "GetModuleInformation"
GetModuleInformation = getattr(ct.WinDLL("kernel32"), get_module_information_func_name, getattr(ct.WinDLL("psapi"), get_module_information_func_name))
GetModuleInformation.argtypes = [wt.HANDLE, wt.HMODULE, ct.POINTER(MODULEINFO)]
GetModuleInformation.restype = wt.BOOL


def get_base_address_original(process_handle, module_handle):
    module_file_name = wproc.GetModuleFileNameEx(process_handle, module_handle)
    print("    File for module {0:d}: {1:s}".format(module_handle, module_file_name))
    module_base_address = wapi.GetModuleHandle(module_file_name)
    return module_base_address


def get_base_address_new(process_handle, module_handle):
    module_info = MODULEINFO()
    res = GetModuleInformation(process_handle.handle, module_handle, ct.byref(module_info))
    print("    Result: {0:}, Base: {1:d}, Size: {2:d}".format(res, module_info.lpBaseOfDll, module_info.SizeOfImage))
    if not res:
        print("    {0:s} failed: {1:d}".format(get_module_information_func_name, getattr(ct.WinDLL("kernel32"), "GetLastError")()))
    return module_info.lpBaseOfDll


def main(*argv):
    pid = int(argv[0]) if argv and argv[0].isdecimal() else wapi.GetCurrentProcessId()
    print("Working on pid {0:d}".format(pid))
    process_handle = wapi.OpenProcess(wcon.PROCESS_ALL_ACCESS, False, pid)
    print("Process handle: {0:d}".format(process_handle.handle))
    module_handles = wproc.EnumProcessModules(process_handle)
    print("Loaded modules: {0:}".format(module_handles))
    module_index = 0  # 0 - the executable itself
    module_handle = module_handles[module_index]
    get_base_address_funcs = [
        #get_base_address_original,  # Original behavior moved in a function
        get_base_address_new,
    ]
    for get_base_address in get_base_address_funcs:
        print("\nAttempting {0:s}".format(get_base_address.__name__))
        try:
            module_base_address = get_base_address(process_handle, module_handle)
            print("    Base address: 0x{0:016X} ({1:d})".format(module_base_address, module_base_address))
        except:
            tb.print_exc()
    process_handle.close()
    #input("\nPress ENTER to exit> ")


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

输出:

e:\Work\Dev\Whosebug\q059610466>"e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Working on pid 59608
Process handle: 452
Loaded modules: (140696816713728, 140714582343680, 140714572513280, 140714535354368, 140714547544064, 140713592946688, 140714443341824, 140714557898752, 140714556325888, 140714550362112, 140714414964736, 140714562486272, 140714532798464, 140714555473920, 140714548592640, 140714533322752, 140714531946496, 140714553769984, 140714555670528, 140714558750720, 140714581426176, 140714556129280, 140714546036736, 140714518052864, 140714532601856, 140714524737536, 140714210361344, 1797128192, 140714574151680, 140714535026688, 140714557046784, 140714538172416, 140714531291136, 140714530963456, 140714530766848, 140714530832384, 1796931584, 140714561044480, 140714573299712, 140714215014400, 140714529849344, 1798438912, 140714559995904, 140714167042048)

Attempting get_base_address_new
    Result: 1, Base: 140696816713728, Size: 110592
    Base address: 0x00007FF687C80000 (140696816713728)

Done.

e:\Work\Dev\Whosebug\q059610466>:: Attempting to run with Task Manager pid
e:\Work\Dev\Whosebug\q059610466>"e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py 22784
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Working on pid 22784
Process handle: 480
Loaded modules: (140699900903424, 140714582343680, 140714572513280, 140714535354368, 140714547544064, 140714573299712, 140714531946496, 140714550362112, 140714562486272, 140714532798464, 140714530963456, 140714530766848, 140714556981248, 140714557898752, 140714556325888, 140714555473920, 140714365222912, 140714548592640, 140714496753664, 140714533322752, 140714553769984, 140714574151680, 140714535026688, 140714557046784, 140714538172416, 140714581426176, 140714558750720, 140714531291136, 140714530832384, 140714546036736, 140714444521472, 140714567467008, 140714532601856, 140714468966400, 140714452385792, 140714267115520, 140714510843904, 140714478731264, 140713698263040, 140714510254080, 140714556129280, 140714565435392, 140714110091264, 140714491379712, 140714455007232, 140714514382848, 140714459529216, 140714281140224, 140714370859008, 140714471260160, 140714566746112, 140713839362048, 140714555670528, 140714171695104, 140714508615680, 140714514841600, 140714029154304, 140714036625408, 140714329636864, 140714447011840, 140714434691072, 140714470866944, 140714561044480, 140714520870912, 140714469883904, 140714494787584, 140714293592064, 140713999335424, 140714400743424, 140714497605632, 140714502193152, 140714197254144, 140714415030272, 140714035576832, 140714065854464, 140714513006592, 140714529652736, 140714512809984, 140714495049728, 140714038657024, 140714371448832, 140714421911552, 140714325966848, 140714196074496, 140714057924608, 140714058317824, 140714064281600, 140714058121216, 140714519756800, 140714327539712, 140714311614464, 140714501079040, 140714546167808, 140714531422208, 140714531553280, 140714557767680, 140714518052864, 140714524737536, 140714167631872, 140714528669696, 140714331865088, 140714310369280, 140714310238208, 140714520018944, 140714458939392, 2018133999616, 140714401988608, 2018141863936, 140714514644992, 140714454810624, 140714294640640)

Attempting get_base_address_new
    Result: 1, Base: 140699900903424, Size: 1105920
    Base address: 0x00007FF73F9D0000 (140699900903424)

Done.



更新#0

根据[MS.Docs]: MODULEINFO structure备注部分,强调仍然是我的):

The load address of a module is the same as the HMODULE value.

所以,事情似乎很简单。

code01.py:

#!/usr/bin/env python3

import sys
import win32api as wapi
import win32process as wproc
import win32con as wcon


def main(*argv):
    pid = int(argv[0]) if argv and argv[0].isdecimal() else wapi.GetCurrentProcessId()
    print("Working on pid {0:d}".format(pid))
    process_handle = wapi.OpenProcess(wcon.PROCESS_ALL_ACCESS, False, pid)
    print("  Process handle: {0:d}".format(process_handle.handle))
    module_handles = wproc.EnumProcessModules(process_handle)
    module_handles_count = len(module_handles)
    print("  Loaded modules count: {0:d}".format(module_handles_count))
    module_index = 0  # 0 - the executable itself
    if module_index > module_handles_count:
        module_index = 0
    module_handle = module_handles[module_index]
    module_file_name = wproc.GetModuleFileNameEx(process_handle, module_handle)
    print("  File [{0:s}] (index {1:d}) is loaded at address 0x{2:016X} ({3:d})".format(module_file_name, module_index, module_handle, module_handle))
    process_handle.close()


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    main(*sys.argv[1:])
    print("\nDone.")

输出:

e:\Work\Dev\Whosebug\q059610466>"e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code01.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Working on pid 7184
  Process handle: 456
  Loaded modules count: 43
  File [e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe] (index 0) is loaded at address 0x00007FF687C80000 (140696816713728)

Done.

e:\Work\Dev\Whosebug\q059610466>:: Attempting to run with Task Manager pid
e:\Work\Dev\Whosebug\q059610466>"e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code01.py 22784
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 64bit on win32

Working on pid 22784
  Process handle: 624
  Loaded modules count: 111
  File [C:\WINDOWS\system32\taskmgr.exe] (index 0) is loaded at address 0x00007FF73F9D0000 (140699900903424)

Done.