I am trying to get the base-address of a process in Windows (64-bit), with Python3, assuming to know the PID.
I looked over all questions here on stack, but the solutions are old/not working.
I assume to have the PID of the process in a variable called pid.
One of the many pieces of code I tried is
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()
But I get error on GetModuleHandle: 'Impossible to find the specified module'.
Thank you for the help.
According to [MS.Docs]: GetModuleHandleW function (emphasis is mine):
Retrieves a module handle for the specified module. The module must have been loaded by the calling process.
That means that it will work fine for the current process, but for any other one you'd get Undefined Behavior, because you try retrieving:
The .dll (or .exe) name from the other process (GetModuleFileNameEx call)
The handle for the name at previous step (GetModuleHandle call) but in the current process (if loaded), which makes no sense
Although there's no clear documentation on this topic (or at least I couldn't find any), the handle is the base address. This is a principle that you also rely on (calling GetModuleHandle), but you can use the values returned by EnumProcessModules directly (look at the example below, the values are the same).
If you want to be rigorous, you could use [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.")
Output:
e:\Work\Dev\StackOverflow\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\StackOverflow\q059610466>:: Attempting to run with Task Manager pid
e:\Work\Dev\StackOverflow\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.
Update #0
According to [MS.Docs]: MODULEINFO structure (Remarks section, emphasis still mine):
The load address of a module is the same as the HMODULE value.
So, things seem to be pretty straightforward.
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.")
Output:
e:\Work\Dev\StackOverflow\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\StackOverflow\q059610466>:: Attempting to run with Task Manager pid
e:\Work\Dev\StackOverflow\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.
I use the netifaces module.
import netifaces
print netifaces.interfaces()
but this shows the result below:
['{CDC97813-CC28-4260-BA1E-F0CE3081DEC7}',
'{846EE342-7039-11DE-9D20-806E6F6E6963}',
'{A51BA5F0-738B-4405-975F-44E67383513F}',
'{A646FA85-2EC6-4E57-996E-96E1B1C5CD59}',
'{B5DC7787-26DC-4540-8424-A1D5598DC175}']
I want to get a "friendly" interface name like "Local Area Connection" in Windows.
How can I get that?
It looks like netifaces leaves it up to us to pull the information out of the Windows Registry. The following functions work for me under Python 3.4 on Windows 8.1.
To get the connection name ...
import netifaces as ni
import winreg as wr
from pprint import pprint
def get_connection_name_from_guid(iface_guids):
iface_names = ['(unknown)' for i in range(len(iface_guids))]
reg = wr.ConnectRegistry(None, wr.HKEY_LOCAL_MACHINE)
reg_key = wr.OpenKey(reg, r'SYSTEM\CurrentControlSet\Control\Network\{4d36e972-e325-11ce-bfc1-08002be10318}')
for i in range(len(iface_guids)):
try:
reg_subkey = wr.OpenKey(reg_key, iface_guids[i] + r'\Connection')
iface_names[i] = wr.QueryValueEx(reg_subkey, 'Name')[0]
except FileNotFoundError:
pass
return iface_names
x = ni.interfaces()
pprint(get_connection_name_from_guid(x))
.. which on my machine produces:
['Local Area Connection* 12',
'Bluetooth Network Connection',
'Wi-Fi',
'Ethernet',
'VirtualBox Host-Only Network',
'(unknown)',
'isatap.{4E4150B0-643B-42EA-AEEA-A14FBD6B1844}',
'isatap.{BB05D283-4CBF-4514-B76C-7B7EBB2FC85B}']
To get the driver name ...
import netifaces as ni
import winreg as wr
from pprint import pprint
def get_driver_name_from_guid(iface_guids):
iface_names = ['(unknown)' for i in range(len(iface_guids))]
reg = wr.ConnectRegistry(None, wr.HKEY_LOCAL_MACHINE)
reg_key = wr.OpenKey(reg, r'SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}')
for i in range(wr.QueryInfoKey(reg_key)[0]):
subkey_name = wr.EnumKey(reg_key, i)
try:
reg_subkey = wr.OpenKey(reg_key, subkey_name)
guid = wr.QueryValueEx(reg_subkey, 'NetCfgInstanceId')[0]
try:
idx = iface_guids.index(guid)
iface_names[idx] = wr.QueryValueEx(reg_subkey, 'DriverDesc')[0]
except ValueError:
pass
except PermissionError:
pass
return iface_names
x = ni.interfaces()
pprint(get_driver_name_from_guid(x))
... which gives me:
['Microsoft Wi-Fi Direct Virtual Adapter',
'Bluetooth Device (Personal Area Network)',
'Dell Wireless 1395 WLAN Mini-Card',
'Broadcom 440x 10/100 Integrated Controller',
'VirtualBox Host-Only Ethernet Adapter',
'(unknown)',
'Microsoft ISATAP Adapter',
'Microsoft ISATAP Adapter']
The Scapy module has a built in get_windows_if_list() that works well. (I shortened the output a bit)
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> get_windows_if_list()
[
{'name': 'Realtek USB GbE Family Controller', 'win_index': '17', 'description': 'Ethernet', 'guid': '<guid>', 'mac': '<mac>', 'netid': 'Ethernet'},
{'name': 'Intel(R) Dual Band Wireless-AC 8260', 'win_index': '5', 'description': 'Wi-Fi', 'guid': '<guid>', 'mac': '<mac>', 'netid': 'Wi-Fi'}
]
We can also use Windows WMI:
import wmi
c = wmi.WMI()
qry = "select Name from Win32_NetworkAdapter where NetEnabled=True and NetConnectionStatus=2"
lst = [o.Name for o in c.query(qry)]
print(lst)
yields on my machine:
['Realtek PCIe GBE Family Controller', 'VMware Virtual Ethernet Adapter for VMnet1', 'VMware Virtual Ethernet Adapter for VMnet8', 'VirtualBox Host-Only Ethernet Adapter']
MSDN: Win32_NetworkAdapter class
Extending on MaxU answer
More accurate/refined way
Select Index from Win32_NetworkAdapterConfiguration WHERE IPEnabled = True or (ServiceName<>''
AND ServiceName<>'AsyncMac'
AND ServiceName<>'VMnetx' AND ServiceName<>'VMnetadapter' AND ServiceName<>'Rasl2tp' AND ServiceName<>'msloop' AND ServiceName<>'PptpMiniport'
AND ServiceName<>'Raspti' AND ServiceName<>'NDISWan' AND ServiceName<>'NdisWan4' AND ServiceName<>'RasPppoe'
AND ServiceName<>'NdisIP' AND Description<>'PPP Adapter.') AND MACAddress is not NULL
and then fire a query with respect to
SELECT * FROM Win32_NetworkAdapter where index= <Index>
It's a lot easier in PowerShell:
Get-WmiObject -Class Win32_NetworkAdapterConfiguration |
Select-Object Description, SettingID, MACAddress |
Format-Table -AutoSize
If you know the IP Address which your Interface uses, you could simply do something like this:
import netifaces as ni
def get_interfaces():
ifaces = ni.interfaces()
for iface in ifaces:
try:
ip = ni.ifaddresses(iface)[ni.AF_INET][0]["addr"]
print(f"IP: {ip} from Interface {iface}")
except:
pass
Here
the documentation of Scapy (scapy.interfaces.NetworkInterface)
NetworkInterface class have multiple data variables
class NetworkInterface(object):
def __init__(self,
provider, # type: InterfaceProvider
data=None, # type: Optional[Dict[str, Any]]
):
# type: (...) -> None
self.provider = provider
self.name = ""
self.description = ""
self.network_name = ""
self.index = -1
self.ip = None # type: Optional[str]
self.ips = defaultdict(list) # type: DefaultDict[int, List[str]]
self.mac = None # type: Optional[str]
self.dummy = False
if data is not None:
self.update(data)
here's how you can get name
from scapy.all import *
l=get_if_list()
dict=IFACES.data
for item in l:
print(dic[item].name)
here's how you can get Driver name
from scapy.all import *
l=get_if_list()
dict=IFACES.data
for item in l:
print(dic[item].description)
You can start an interactive console from inside a script with following code:
import code
# do something here
vars = globals()
vars.update(locals())
shell = code.InteractiveConsole(vars)
shell.interact()
When I run the script like so:
$ python my_script.py
an interactive console opens:
Python 2.7.2+ (default, Jul 20 2012, 22:12:53)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>
The console has all globals and locals loaded which is great since I can test stuff easily.
The problem here is that arrows don't work as they normally do when starting an Python console. They simply display escaped characters to the console:
>>> ^[[A^[[B^[[C^[[D
This means that I can't recall previous commands using the up/down arrow keys and I can't edit the lines with the left/right arrow keys either.
Does anyone know why is that and/or how to avoid that?
Check out readline and rlcompleter:
import code
import readline
import rlcompleter
# do something here
vars = globals()
vars.update(locals())
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
shell = code.InteractiveConsole(vars)
shell.interact()
This is the one I use:
def debug_breakpoint():
"""
Python debug breakpoint.
"""
from code import InteractiveConsole
from inspect import currentframe
try:
import readline # noqa
except ImportError:
pass
caller = currentframe().f_back
env = {}
env.update(caller.f_globals)
env.update(caller.f_locals)
shell = InteractiveConsole(env)
shell.interact(
'* Break: {} ::: Line {}\n'
'* Continue with Ctrl+D...'.format(
caller.f_code.co_filename, caller.f_lineno
)
)
For example, consider the following script:
a = 10
b = 20
c = 'Hello'
debug_breakpoint()
a = 20
b = c
c = a
mylist = [a, b, c]
debug_breakpoint()
def bar():
a = '1_one'
b = '2+2'
debug_breakpoint()
bar()
When executed, this file shows to following behavior:
$ python test_debug.py
* Break: test_debug.py ::: Line 24
* Continue with Ctrl+D...
>>> a
10
>>>
* Break: test_debug.py ::: Line 32
* Continue with Ctrl+D...
>>> b
'Hello'
>>> mylist
[20, 'Hello', 20]
>>> mylist.append(a)
>>>
* Break: test_debug.py ::: Line 38
* Continue with Ctrl+D...
>>> a
'1_one'
>>> mylist
[20, 'Hello', 20, 20]