How to share mmap between python and node processes - python

I'm trying to share memory between a python process and a nodejs process started from the python process using an anonymous mmap. Essentially, the python process begins, initializes the mmap and starts a subprocess using either call or Popen to launch a child that runs some node code. This nodejs code uses mmap to try to access the same area in memory. However I get two different mappings and no data is shared between them. Why is this?
import mmap, math, os
from subprocess import call
mm = mmap.mmap( -1, 1024,
flags=mmap.MAP_SHARED | mmap.MAP_ANONYMOUS,
prot= mmap.PROT_READ | mmap.PROT_WRITE )
mm.seek(0)
mm.write('hello world!\n'.encode('utf-8'))
call([
'node', '-e',
"""
const mmap = require('mmap.js');
const fileBuf = mmap.alloc(
1024,
mmap.PROT_READ | mmap.PROT_WRITE,
mmap.MAP_SHARED| mmap.MAP_ANONYMOUS,
-1,
0
)
console.log(fileBuf.toString('utf-8'));
"""
])
The mmap.js that I am using is a NAPI of the original mmap c function. This is the github for this library.
EDIT:
Thanks to 'that other guy' for his answer. It was the correct one. Here's some sample code that works out of the box!:
test_mmap.py
import os, ctypes, posix_ipc, sys, mmap
from subprocess import call
SHARED_MEMORY_NAME = "/shared_memory"
memory = posix_ipc.SharedMemory(SHARED_MEMORY_NAME, posix_ipc.O_CREX,
size=1024)
mapFile = mmap.mmap(memory.fd, memory.size)
memory.close_fd()
mapFile.seek(0)
mapFile.write("Hello world!\n".encode('utf-8'))
mapFile.seek(0)
print("FROM PYTHON MAIN PROCESS: ", mapFile.readline().decode('utf-8'))
mapFile.seek(0)
call([
"node", "./test_mmap.js", SHARED_MEMORY_NAME
])
mapFile.close()
posix_ipc.unlink_shared_memory(SHARED_MEMORY_NAME)
test_mmap.js
const args = process.argv;
const mmap = require('mmap.js');
const shm = require('nodeshm');
const SHM_FILE_NAME=args[args.length-1];
let fd = shm.shm_open(SHM_FILE_NAME, shm.O_RDWR, 0600);
if (fd == -1){
console.log("FD COULD NOT BE OPENED!");
throw "here";
}
let mm = mmap.alloc(1024, mmap.PROT_READ | mmap.PROT_WRITE, mmap.MAP_SHARED, fd, 0);
console.log("FROM NODE: ", mm.slice(0, mm.indexOf('\n')).toString('utf-8'));
Sample output:
FROM PYTHON MAIN PROCESS: Hello world!
FROM NODE: Hello world!

Fortunately this doesn't work: imagine how confusing if all of the system's MAP_ANONYMOUS mappings were against the same area and kept overwriting each other.
Instead, use shm_open to create a new handle you can mmap in both processes. This is a portable wrapper around the equally valid but less portable strategy of creating and mmap'ing a file in /dev/shm/.

Related

Python ctypes - Receiving ERROR_PARTIAL_COPY when trying to ReadProcessMemory

My program, running elevated on Windows 10:
gets the PID of a running notepad.exe process
receives a handle to it via OpenProcess
Enumerates the baseAddress of the process module with the name notepad.exe on it
calls ReadProcessMemory
import ctypes
from ctypes import wintypes
import win32process
import psutil
targetProcess = "notepad.exe"
PROCESS_ALL_ACCESS = 0x1F0FFF
BUFFER_SIZE = 200
def getpid():
for proc in psutil.process_iter():
if proc.name() == targetProcess:
return proc.pid
def main():
status = ctypes.windll.ntdll.RtlAdjustPrivilege(20, 1, 0, ctypes.byref(ctypes.c_bool()))
if(status == -1073741727):
print("STATUS_PRIVILEGE_NOT_HELD - A required privilege is not held by the client.")
hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, getpid()) # handle to process
lpBuffer = ctypes.create_string_buffer(BUFFER_SIZE) # Buffer we want to write results to
targetProcessBaseAddress = None # base address of the target processes entry module
modules = win32process.EnumProcessModules(hProcess) # Retreive modules of target process
for module in modules:
name = str(win32process.GetModuleFileNameEx(hProcess, module))
if targetProcess in name:
targetProcessBaseAddress = hex(module)
count = ctypes.c_ulong(0)
res = ctypes.windll.kernel32.ReadProcessMemory(hProcess, targetProcessBaseAddress, ctypes.byref(lpBuffer), BUFFER_SIZE, ctypes.byref(count))
if res == 0:
err = ctypes.windll.kernel32.GetLastError()
if (err == 299):
print("ERROR_PARTIAL_COPY - Only part of a ReadProcessMemory or WriteProcessMemory request was completed.")
else:
print(err)
else:
print(lpBuffer.raw)
if __name__ == '__main__':
main()
Above is done via python3.8 using the native ctypes library.
I'm expecting to see a hexdump or any data other than 0x00,0x00.. but it seems my error is somewhere in the arguments provided to ReadProcessMemory, which is assumed due to error 299 returned from GetLastError(), which indicates:
"ERROR_PARTIAL_COPY - Only part of a ReadProcessMemory or WriteProcessMemory request was completed."
Not sure where I'm messing up, would be very grateful for suggestions and assistance!
ReadProcessMemory second argument is a LPCVOID (long pointer to const void*) but you're passing the result of hex which returns a string (which then would translate to a pointer to string in ctypes context).
Follow #CristiFati comment and use ctypes argtypes and restype which would have spotted the problem immediately.
Do not use directly GetLastError from the win32 API. The interpreter is free to call any Windows API during its life, thus when you call this API you don't know if it's the result from your script or an API that was called by the interpreter for its own purpose. For this, ctypes proposes a specific variable which caches the result in the form of ctypes.get_last_error.
The best way to do that is to start your script with something like that:
import ctypes
# obtain kernel32 WinDLL ensuring that we want to cache the last error for each API call.
kernel32 = ctypes.WinDLL("kernel32", use_last_error = True)
# start prototyping your APIs
OpenProcess = kernel32.OpenProcess
OpenProcess.argtypes = [ ... ]
OpenProcess.restype = ...
# then call the api
res = OpenProcess( ... )
#ensure you check the result by calling the cached last error
if not res:
err = ctypes.get_last_error()
# you might also raise
raise ctypes.WinError(err)

ctypes, GetErrorCode 6, LoadLibrary and Modulehandle returning None?

i am currently learning more about ctypes and its functions and what I'm trying to do is to create a script to WriteProcessMemory into notepad via its PID(process ID). However, when i tried to execute my script, notepad just instantly crashes. I am following the tutorial from this, which i think is the same as the "Gray Hat for Hacking Python" book. By right, the shell code executed is supposed to create a message box.
Here is my code.
import os
import colorama
from colorama import Fore, Back, Style
import win32com.client
from ctypes import *
from ctypes import wintypes
import ctypes
from ctypes.wintypes import BOOL
from ctypes.wintypes import DWORD
from ctypes.wintypes import HANDLE
from ctypes.wintypes import LPVOID
from ctypes.wintypes import LPCVOID
from ctypes.wintypes import LPCWSTR
colorama.init()
kernel32 = ctypes.WinDLL('Kernel32', use_last_error=True)
LPCSTR = LPCTSTR = ctypes.c_char_p
LPDWORD = PDWORD = ctypes.POINTER(DWORD)
class _SECURITY_ATTRIBUTES(ctypes.Structure):
_fields_ = [('nLength', DWORD),
('lpSecurityDescriptor', LPVOID),
('bInheritHandle', BOOL),]
SECURITY_ATTRIBUTES = _SECURITY_ATTRIBUTES
LPSECURITY_ATTRIBUTES = ctypes.POINTER(_SECURITY_ATTRIBUTES)
LPTHREAD_START_ROUTINE = LPVOID
OpenProcess = kernel32.OpenProcess
OpenProcess.restype = HANDLE
OpenProcess.argtypes = (DWORD, BOOL, DWORD)
VirtualAllocEx = kernel32.VirtualAllocEx
VirtualAllocEx.restype = LPVOID
VirtualAllocEx.argtypes = (HANDLE, LPVOID, ctypes.c_size_t, DWORD, DWORD)
ReadProcessMemory = kernel32.ReadProcessMemory
ReadProcessMemory.restype = BOOL
ReadProcessMemory.argtypes = (HANDLE, LPCVOID, LPVOID, DWORD, DWORD)
WriteProcessMemory = kernel32.WriteProcessMemory
WriteProcessMemory.restype = BOOL
WriteProcessMemory.argtypes = (HANDLE, LPVOID, LPCVOID, DWORD, ctypes.c_int)
CreateRemoteThread = kernel32.CreateRemoteThread
CreateRemoteThread.restype = HANDLE
CreateRemoteThread.argtypes = (HANDLE, LPSECURITY_ATTRIBUTES, ctypes.c_size_t , LPTHREAD_START_ROUTINE, LPVOID, DWORD, ctypes.c_ulong)
GetLastError = kernel32.GetLastError
GetLastError.restype = DWORD
GetLastError.argtypes = ()
GetModuleHandle = kernel32.GetModuleHandleA
GetModuleHandle.restype = HANDLE
GetModuleHandle.argtypes = (LPCWSTR,)
GetProcAddress = kernel32.GetProcAddress
GetProcAddress.restype = LPVOID
GetProcAddress.argtypes = (HANDLE, LPCWSTR)
# https://www.aldeid.com/wiki/Process-Security-and-Access-Rights
PROCESS_VM_READ = 0x0010 # Required to read memory in a process using ReadProcessMemory.
PROCESS_VM_WRITE = 0x0020
PROCESS_VM_OPERATION = 0x0008 # Required to write to memory in a process using WriteProcessMemory.
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_CREATE_THREAD = 0x0002
PROCESS_ALL_ACCESS = (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD) #0x1F0FFF
print(Fore.RED + 'Retrieving PIDs...')
WMI= win32com.client.GetObject('winmgmts:')
processes = WMI.ExecQuery('SELECT * from win32_process')
print(Fore.GREEN)
process_list = [i.Properties_('ProcessId').Value for i in processes] # list of available processes
for process in processes:
print(process.Properties_('ProcessId').Value , " - " , process.Properties_('Name').Value)
PID = int(input('Enter the PID of the process '))
# https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess
process_handle = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, PID) # creating the handle
if not process_handle:
print ("Couldn't acquire a handle to PID: %s" % PID)
shellcode = "C:\\Users\\User\\Desktop\\py\\injector\\hello-world-x64.dll"
# https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
memory_alloc = kernel32.VirtualAllocEx(process_handle,0, len(shellcode), (0x1000 | 0x2000), 0x40) # allocating memory to the process
write = kernel32.WriteProcessMemory(process_handle, memory_alloc, shellcode, len(shellcode), 0)
ModuleHandle = kernel32.GetModuleHandleA('kernel32.dll')
LoadLibraryA = kernel32.GetProcAddress(ModuleHandle,"LoadLibraryA")
if not kernel32.CreateRemoteThread(process_handle, None, 0, LoadLibraryA, memory_alloc, 0, 0):
print("Failed injection..")
print("ModuleHandle : ", ModuleHandle)
print("LoadLibrary : ", LoadLibraryA)
print("process handle : ", process_handle)
print("VirtualAllocEx : ",memory_alloc)
print("WriteProcessMemory : ",write)
print(ctypes.GetLastError())
I've tried printing the return values and apparently the one that is giving me error is ModuleHandle and LoadLibrary which is returning a None value. But according to microsoft:
If the function succeeds, the return value is nonzero.
If the function fails, the return value is 0 (zero). To get extended error information, call GetLastError. The function fails if the requested write operation crosses into an area of the process that is inaccessible.
I've also tried the GetLastError() method which returned 6, which upon googling, it refers to "invalid handler".
If it helps, my OS, notepad, VScode(my ide), python(3.6.8) are all 64bit.
I apologise for the messy code and please feel free to correct me as i am a complete beginner in this area.
Edit
Here is the image of my printed outputs. I have also tried LoadLibraryW and GetModuleHandleW but it didnt work either, my notepad just crashes. The dll that im using is a generic DLL file that just spawns a messagebox saying "Hello World"
Okay, there are many mistakes I've made writing this script and #eryksun has given many brilliant answers in the comment section. And i am writing this answer to consolidate what I've learnt.
1) I should've used kernel32 = ctypes.WinDLL('Kernel32', use_last_error=True) instead of kernel32 = ctypes.windll.kernel32. This avoids conflicts with other modules that use windll. It also enables protection for the thread's LastErrorValue. In this case, use ctypes.get_last_error() and ctypes.set_last_error(err) instead of directly calling WinAPI GetLastError and SetLastError.
2) WriteProcessMemory.argtypes = (HANDLE, LPVOID, LPCVOID, DWORD, ctypes.c_int) was set wrongly. The argtypes according to the documentation, it should be:
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPCVOID lpBuffer,
SIZE_T nSize,
SIZE_T *lpNumberOfBytesWritten
);
where the last 2 arguments should be [HANDLE, LPVOID, LPCVOID, SIZE_T, PSIZE_T].
3) PROCESS_ALL_ACCESS should only take in the necessary rights needed by CreateRemoteThread and WriteProcessMemory which are PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION.
4) Instead of allocating the size of the bytes I am passing to be len(shellcode), it should be (len(shellcode) + 1) * WCHAR_SIZE.
In general you should factor in the null terminator when copying a string, e.g. use len(dll_path) + 1. In this case you're committing a new page of memory (4 KiB on x86 and x64 systems), which is initially all zeros.
If you're using Python 3, then the DLL path is passed as a wide-character, null-terminated string, which explains the need for plus 1 (the trailing null character) and the need to multiply by WCHAR_SIZE (two bytes per character).
WriteProcessMemory is just writing the path as a string in the address space of the target process. This is passed as a parameter to LoadLibraryW (the native "W" version for a wide-character Unicode string), which is called in the target process on a new remote thread. Notice that LoadLibraryW is at the same address in the target process as our current process, because kernel32.dll is always mapped at its preferred base address, and it's always loaded in a Windows process. That's not necessarily the case for most other DLLs.
5) GetModuleHandleA and LoadLibraryA should be replaced with their respective W function. Moreover, The GetModuleHandleW and GetProcAddress steps are unnecessary. ctypes already does this for you. Just use kernel32.LoadLibraryW. This depends on kernel32.dll always being mapped to the same base address in each process, which I think is true for existing versions of Windows.
DOS and Windows 9x used codepages to encode strings (i.e. a mapping between ordinal values and characters) for a given locale, such as 437 for the U.S., 850 for Western Europe, and 1252 in Windows for both regions. OTOH, Windows NT (1993) was based on Unicode (i.e. one character set that supports all written languages), and it needed to provide compatibility with Windows 9x applications that didn't support Unicode.
NT defined two codepages per locale, an OEM (DOS) codepage and an ANSI (Windows) codepage. Functions had a [W]ide-character version (e.g. GetModuleHandleW) and a wrapped [A]NSI version (e.g. GetModuleHandleA). The wrapper translated between ANSI and Unicode and called the wide-character function. At the API level, the headers defined one or the other, depending on whether UNICODE was defined. Additionally this system defined TCHAR string types such as LPTSTR that are mapped to either the narrow type such as LPSTR or the wide-character type such as LPWSTR
Since Windows XP, all supported versions of Windows have been based on Windows NT, and many new functions added to the API are only available in wide-character versions (e.g. GetLocaleInfoEx; note the lack of a "W" suffix in this case because there's only one version). The old ANSI API and TCHAR types are a legacy now. I recommend only using the native wide-character API with Unicode strings.
Props to #eryksun for being so helpful!

Get python application memory usage

My main goal is to know how much memory my python application takes during execution.
I'm using python 2.7.5 on Windows-32 and Windows-64.
I found a way to get some info about my process here: http://code.activestate.com/recipes/578513-get-memory-usage-of-windows-processes-using-getpro/
Putting the code here for convenience:
"""Functions for getting memory usage of Windows processes."""
__all__ = ['get_current_process', 'get_memory_info', 'get_memory_usage']
import ctypes
from ctypes import wintypes
GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
GetCurrentProcess.argtypes = []
GetCurrentProcess.restype = wintypes.HANDLE
SIZE_T = ctypes.c_size_t
class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
_fields_ = [
('cb', wintypes.DWORD),
('PageFaultCount', wintypes.DWORD),
('PeakWorkingSetSize', SIZE_T),
('WorkingSetSize', SIZE_T),
('QuotaPeakPagedPoolUsage', SIZE_T),
('QuotaPagedPoolUsage', SIZE_T),
('QuotaPeakNonPagedPoolUsage', SIZE_T),
('QuotaNonPagedPoolUsage', SIZE_T),
('PagefileUsage', SIZE_T),
('PeakPagefileUsage', SIZE_T),
('PrivateUsage', SIZE_T),
]
GetProcessMemoryInfo = ctypes.windll.psapi.GetProcessMemoryInfo
GetProcessMemoryInfo.argtypes = [
wintypes.HANDLE,
ctypes.POINTER(PROCESS_MEMORY_COUNTERS_EX),
wintypes.DWORD,
]
GetProcessMemoryInfo.restype = wintypes.BOOL
def get_current_process():
"""Return handle to current process."""
return GetCurrentProcess()
def get_memory_info(process=None):
"""Return Win32 process memory counters structure as a dict."""
if process is None:
process = get_current_process()
counters = PROCESS_MEMORY_COUNTERS_EX()
ret = GetProcessMemoryInfo(process, ctypes.byref(counters),
ctypes.sizeof(counters))
if not ret:
raise ctypes.WinError()
info = dict((name, getattr(counters, name))
for name, _ in counters._fields_)
return info
def get_memory_usage(process=None):
"""Return this process's memory usage in bytes."""
info = get_memory_info(process=process)
return info['PrivateUsage']
if __name__ == '__main__':
import pprint
pprint.pprint(get_memory_info())
And this is the result:
{'PageFaultCount': 1942L,
'PagefileUsage': 4624384L,
'PeakPagefileUsage': 4624384L,
'PeakWorkingSetSize': 7544832L,
'PrivateUsage': 4624384L,
'QuotaNonPagedPoolUsage': 8520L,
'QuotaPagedPoolUsage': 117848L,
'QuotaPeakNonPagedPoolUsage': 8776L,
'QuotaPeakPagedPoolUsage': 117984L,
'WorkingSetSize': 7544832L,
'cb': 44L}
But this does not satisfy me. These results give me the whole python process information while what I need is only my specific application that runs on top of the Python framework.
I saw several memory profilers on the internet and also here in Stack Overflow but they are too big for me. The only information that I need is how much memory my app consumes by itself - without taking into account all the Python framework.
How can I achieve this?
Here is a simple easy pythonic way, based on (os, psutil) modules. Thanks to (Dataman) and (RichieHindle) answers.
import os
import psutil
## - Get Process Id of This Running Script -
proc_id = os.getpid()
print '\nProcess ID: ', proc_id
#--------------------------------------------------
## - Get More Info Using the Process Id
ObjInf = psutil.Process(proc_id)
print '\nProcess %s Info:' % proc_id, ObjInf
#--------------------------------------------------
## - Proccess Name of this program
name = ObjInf.name()
print '\nThis Program Process name:', name
#--------------------------------------------------
## - Print CPU Percentage
CpuPerc = ObjInf.cpu_percent()
print '\nCpu Percentage:', CpuPerc
#---------------------------------------------------
## - Print Memory Usage
memory_inf = ObjInf.memory_full_info()
print '\nMemory Info:', memory_inf, '\n'
## Print available commands you can do with the psutil obj
for c in dir(ObjInf):
print c
If your script is made in python, then your script is python itself, so it wouldn't run without it, thus you have to account for python memory usage also, if you want to see how much memory python consumes by itself just run an empty python script and you will deduct from there, that your script will be the main resources consumer, which happens to be made in python thus python.
Now if you want to check memory usage of a thread then this question might help -> Why does python thread consume so much memory?
Here is my script I am using to find the maximum amount of resources used during the execution of another script. I am using psutilto achieve this. You can tweak the script to make it suitable for your purposes.
import psutil, sys
import numpy as np
from time import sleep
pid = int(sys.argv[1])
delay = int(sys.argv[2])
p = psutil.Process(pid)
max_resources_used = -1
while p.is_running():
## p.memory_info()[0] returns 'rss' in Unix
r = int(p.memory_info()[0] / 1048576.0) ## resources used in Mega Bytes
max_resources_used = r if r > max_resources_used else max_resources_used
sleep(delay)
print("Maximum resources used: %s MB." %np.max(max_resources_used))
Usage:
python script.py pid delay_in_seconds
For example:
python script.py 55356 2
Explanation:
You need to find out the process ID and pass it as an argument to the script plus the time interval for checking the resource usage in seconds (i.e. every how many seconds the script checks the amount of used resources). The script keeps track of the memory usage until the process is running. Finally it returns the maximum amount of memory used in MB.

How to check whether screen is off in Mac/Python?

How do I check whether the screen is off due to the Energy Saver settings in System Preferences under Mac/Python?
Quick and dirty solution: call ioreg and parse the output.
import subprocess
import re
POWER_MGMT_RE = re.compile(r'IOPowerManagement.*{(.*)}')
def display_status():
output = subprocess.check_output(
'ioreg -w 0 -c IODisplayWrangler -r IODisplayWrangler'.split())
status = POWER_MGMT_RE.search(output).group(1)
return dict((k[1:-1], v) for (k, v) in (x.split('=') for x in
status.split(',')))
In my computer, the value for CurrentPowerState is 4 when the screen is on and 1 when the screen is off.
Better solution: use ctypes to get that information directly from IOKit.
The only way i can think off is by using OSX pmset Power Management CML Tool
DESCRIPTION
pmset changes and reads power management settings such as idle sleep timing, wake on administrative
access, automatic restart on power loss, etc.
Refer to the following link, it will provide a great deal of information that should aid you in accomplishing exactly what you are looking for.
http://managingamac.blogspot.com/2012/12/power-assertions-in-python.html
I will include the code provided by the link for "saving and documentation" purposes:
#!/usr/bin/python
import ctypes
import CoreFoundation
import objc
import subprocess
import time
def SetUpIOFramework():
# load the IOKit library
framework = ctypes.cdll.LoadLibrary(
'/System/Library/Frameworks/IOKit.framework/IOKit')
# declare parameters as described in IOPMLib.h
framework.IOPMAssertionCreateWithName.argtypes = [
ctypes.c_void_p, # CFStringRef
ctypes.c_uint32, # IOPMAssertionLevel
ctypes.c_void_p, # CFStringRef
ctypes.POINTER(ctypes.c_uint32)] # IOPMAssertionID
framework.IOPMAssertionRelease.argtypes = [
ctypes.c_uint32] # IOPMAssertionID
return framework
def StringToCFString(string):
# we'll need to convert our strings before use
return objc.pyobjc_id(
CoreFoundation.CFStringCreateWithCString(
None, string,
CoreFoundation.kCFStringEncodingASCII).nsstring())
def AssertionCreateWithName(framework, a_type,
a_level, a_reason):
# this method will create an assertion using the IOKit library
# several parameters
a_id = ctypes.c_uint32(0)
a_type = StringToCFString(a_type)
a_reason = StringToCFString(a_reason)
a_error = framework.IOPMAssertionCreateWithName(
a_type, a_level, a_reason, ctypes.byref(a_id))
# we get back a 0 or stderr, along with a unique c_uint
# representing the assertion ID so we can release it later
return a_error, a_id
def AssertionRelease(framework, assertion_id):
# releasing the assertion is easy, and also returns a 0 on
# success, or stderr otherwise
return framework.IOPMAssertionRelease(assertion_id)
def main():
# let's create a no idle assertion for 30 seconds
no_idle = 'NoIdleSleepAssertion'
reason = 'Test of Pythonic power assertions'
# first, we'll need the IOKit framework
framework = SetUpIOFramework()
# next, create the assertion and save the ID!
ret, a_id = AssertionCreateWithName(framework, no_idle, 255, reason)
print '\n\nCreating power assertion: status %s, id %s\n\n' % (ret, a_id)
# subprocess a call to pmset to verify the assertion worked
subprocess.call(['pmset', '-g', 'assertions'])
time.sleep(5)
# finally, release the assertion of the ID we saved earlier
AssertionRelease(framework, a_id)
print '\n\nReleasing power assertion: id %s\n\n' % a_id
# verify the assertion has been removed
subprocess.call(['pmset', '-g', 'assertions'])
if __name__ == '__main__':
main()
https://opensource.apple.com/source/PowerManagement/PowerManagement-211/pmset/pmset.c
The code relies on IOPMLib, which functions to make assertions, schedule power events, measure thermals, and more.
https://developer.apple.com/documentation/iokit/iopmlib_h
To call these functions through Python, we must go through the IOKit Framework.
https://developer.apple.com/library/archive/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/Introduction/Introduction.html
In order for us to manipulate C data types in Python, we'll use a foreign function interface called ctypes.
http://python.net/crew/theller/ctypes/
Here's the wrapper the author describe's on the page; written by Michael Lynn. The code i posted from the Author's link above is a rewrite of this code to make it more understandable.
https://github.com/pudquick/pypmset/blob/master/pypmset.py

Is there any good and easy-to-use module built in Python for editing memory?

Is there any good and easy-to-use module built in Python for editing memory? Or is there any module like this at all?
What I'm looking for is a way to attach to a process and read from/write to it. Much like how Cheat Engine works. Here's a example of how it works in C++.
Took me a while to find a way of doing this but here's what I came up with!
from ctypes import *
from ctypes.wintypes import *
pid = 0 #the pid of the process, aquired earlier by hand
address = 0x0000 #where to read from while in the memory
OpenProcess = windll.kernel32.OpenProcess
ReadProcessMemory = windll.kernel32.ReadProcessMemory
CloseHandle = windll.kernel32.CloseHandle
PROCESS_ALL_ACCESS = 0x1F0FFF
datadummy = b'.'*200
buffer = c_char_p(datadummy)
bufferSize = len(buffer.value)
bytesRead = c_ulong(0)
processHandle = OpenProcess(PROCESS_ALL_ACCESS, False, int(PID))
ReadProcessMemory(processHandle, address, buffer, bufferSize, byref(bytesRead))
CloseHandle(processHandle)
And to write to the memory I would just add WriteProcessMemory = windll.kernel32.WriteProcessMemory and then call it

Categories

Resources