Monitoring memory addresses in Python [closed] - python

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I need to know how to monitor a memory address and its values in Python.
For example: I have a game that is written in C. I want to write a Python script that read the memory address of my current HitPoints and take actions based on its values.
I already can get the memory addresses with CheatEngine, but I don't know how use this in Python.

Here's a read_process function. The result is either bytes (2.x str), or an array of ctypes structures. The default is to read 1 byte from the process. The optional dtype parameter must be a ctypes type, such as ctypes.c_cint or a ctypes.Structure subclass. It reads an array of the given type and length.
Be careful to avoid dereferencing pointer values. For example, if you pass dtype=c_char_p, then simply indexing the result array will try to dereference a remote pointer in the current process, which will likely crash Python. In a previous answer I wrote a read-only RemotePointer class if you need to handle that case.
ctypes definitions
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
PROCESS_VM_READ = 0x0010
SIZE_T = ctypes.c_size_t
PSIZE_T = ctypes.POINTER(SIZE_T)
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(error)
return args
kernel32.OpenProcess.errcheck = _check_bool
kernel32.OpenProcess.restype = wintypes.HANDLE
kernel32.OpenProcess.argtypes = (
wintypes.DWORD, # _In_ dwDesiredAccess
wintypes.BOOL, # _In_ bInheritHandle
wintypes.DWORD) # _In_ dwProcessId
kernel32.CloseHandle.errcheck = _check_bool
kernel32.CloseHandle.argtypes = (
wintypes.HANDLE,)
kernel32.ReadProcessMemory.errcheck = _check_bool
kernel32.ReadProcessMemory.argtypes = (
wintypes.HANDLE, # _In_ hProcess
wintypes.LPCVOID, # _In_ lpBaseAddress
wintypes.LPVOID, # _Out_ lpBuffer
SIZE_T, # _In_ nSize
PSIZE_T) # _Out_ lpNumberOfBytesRead
read_process definition
def read_process(pid, address, length=1, dtype=ctypes.c_char):
result = (dtype * length)()
nread = SIZE_T()
hProcess = kernel32.OpenProcess(PROCESS_VM_READ, False, pid)
try:
kernel32.ReadProcessMemory(hProcess, address, result,
ctypes.sizeof(result),
ctypes.byref(nread))
finally:
kernel32.CloseHandle(hProcess)
if issubclass(dtype, ctypes.c_char):
return result.raw
return result
example
if __name__ == '__main__':
import os
class DType(ctypes.Structure):
_fields_ = (('x', ctypes.c_int),
('y', ctypes.c_double))
source = (DType * 2)(*[(42, 3.14),
(84, 2.72)])
pid = os.getpid()
address = ctypes.addressof(source)
sink = read_process(pid, address, 2, DType)
for din, dout in zip(source, sink):
assert din.x == dout.x
assert din.y == dout.y
size = ctypes.sizeof(source)
buf_source = ctypes.string_at(source, size)
buf_sink = read_process(pid, address, size)
assert buf_source == buf_sink

Related

Cancel a stalled file copy in python on windows

On windows, I want to copy a bunch of files over a network with Python. Sometimes, the network is not responding, and the copy is stalled. I want to check, if that happens, and skip the file in question, when that happens. By asking this related question here, I found out about the CopyFileEx function, that allows the use of a callback function, that can abort the file copy.
The implementation in Python looks like that:
import win32file
def Win32_CopyFileEx( ExistingFileName, NewFileName, Canc = False):
win32file.CopyFileEx(
ExistingFileName, # PyUNICODE | File to be copied
NewFileName, # PyUNICODE | Place to which it will be copied
Win32_CopyFileEx_ProgressRoutine, # CopyProgressRoutine | A python function that receives progress updates, can be None
Data = None, # object | An arbitrary object to be passed to the callback function
Cancel = Canc, # boolean | Pass True to cancel a restartable copy that was previously interrupted
CopyFlags = win32file.COPY_FILE_RESTARTABLE, # int | Combination of COPY_FILE_* flags
Transaction = None # PyHANDLE | Handle to a transaction as returned by win32transaction::CreateTransaction
)
From the documentation of the CopyFileEx function, I can see two possibilities of cancelation of a running copy.
pbCancel [in, optional] If this flag is set to TRUE during the copy operation, the operation is canceled. Otherwise, the copy
operation will continue to completion.
I could not figure out a way how to do that. I tried calling the same function with the same file handles again but with the cancel flag set to TRUE, but that leads in an error, because of the file in question being in use by another process.
Another possibility seems to be the callback function:
lpProgressRoutine [in, optional] The address of a callback function of
type LPPROGRESS_ROUTINE that is called each time another portion of
the file has been copied. This parameter can be NULL. For more
information on the progress callback function, see the
CopyProgressRoutine function.
The documentation of this ProgressRoutine states, that this callback is either called when the copy is started or when a junk of the file is finished copying. The callback function can cancel the copy process if it returns 1 or 2 ( cancel, stop). However, this callback function seems to not being called, when the copy of a junk is stalled.
So my question is: How I can cancel this copy on a per-file-basis when it is stalled?
win32file.CopyFileEx doesn't allow passing Cancel as anything but a boolean or integer value. In the API it's an LPBOOL pointer, which allows the caller to set its value concurrently in another thread. You'll have to use ctypes, Cython, or a C extension to get this level of control. Below I've written an example using ctypes.
If canceling the copy doesn't work because the thread is blocked on synchronous I/O, you can try calling CancelIoEx on the file handles that you're passed in the progress routine, or CancelSynchronousIo to cancel all synchronous I/O for the thread. These I/O cancel functions were added in Windows Vista. They're not available in Windows XP, in case you're still supporting it.
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
COPY_FILE_FAIL_IF_EXISTS = 0x0001
COPY_FILE_RESTARTABLE = 0x0002
COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x0004
COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x0008
COPY_FILE_COPY_SYMLINK = 0x0800
COPY_FILE_NO_BUFFERING = 0x1000
CALLBACK_CHUNK_FINISHED = 0
CALLBACK_STREAM_SWITCH = 1
PROGRESS_CONTINUE = 0
PROGRESS_CANCEL = 1
PROGRESS_STOP = 2
PROGRESS_QUIET = 3
ERROR_REQUEST_ABORTED = 0x04D3
if not hasattr(wintypes, 'LPBOOL'):
wintypes.LPBOOL = ctypes.POINTER(wintypes.BOOL)
def _check_bool(result, func, args):
if not result:
raise ctypes.WinError(ctypes.get_last_error())
return args
LPPROGRESS_ROUTINE = ctypes.WINFUNCTYPE(
wintypes.DWORD, # _Retval_
wintypes.LARGE_INTEGER, # _In_ TotalFileSize
wintypes.LARGE_INTEGER, # _In_ TotalBytesTransferred
wintypes.LARGE_INTEGER, # _In_ StreamSize
wintypes.LARGE_INTEGER, # _In_ StreamBytesTransferred
wintypes.DWORD, # _In_ dwStreamNumber
wintypes.DWORD, # _In_ dwCallbackReason
wintypes.HANDLE, # _In_ hSourceFile
wintypes.HANDLE, # _In_ hDestinationFile
wintypes.LPVOID) # _In_opt_ lpData
kernel32.CopyFileExW.errcheck = _check_bool
kernel32.CopyFileExW.argtypes = (
wintypes.LPCWSTR, # _In_ lpExistingFileName
wintypes.LPCWSTR, # _In_ lpNewFileName
LPPROGRESS_ROUTINE, # _In_opt_ lpProgressRoutine
wintypes.LPVOID, # _In_opt_ lpData
wintypes.LPBOOL, # _In_opt_ pbCancel
wintypes.DWORD) # _In_ dwCopyFlags
#LPPROGRESS_ROUTINE
def debug_progress(tsize, ttrnsfr, stsize, sttrnsfr, stnum, reason,
hsrc, hdst, data):
print('ttrnsfr: %d, stnum: %d, stsize: %d, sttrnsfr: %d, reason: %d' %
(ttrnsfr, stnum, stsize, sttrnsfr, reason))
return PROGRESS_CONTINUE
def copy_file(src, dst, cancel=None, flags=0,
cbprogress=None, data=None):
if isinstance(cancel, int):
cancel = ctypes.byref(wintypes.BOOL(cancel))
elif cancel is not None:
cancel = ctypes.byref(cancel)
if cbprogress is None:
cbprogress = LPPROGRESS_ROUTINE()
kernel32.CopyFileExW(src, dst, cbprogress, data, cancel, flags)
Example
if __name__ == '__main__':
import os
import tempfile
import threading
src_fd, src = tempfile.mkstemp()
os.write(src_fd, os.urandom(16 * 2 ** 20))
os.close(src_fd)
dst = tempfile.mktemp()
cancel = wintypes.BOOL(False)
t = threading.Timer(0.001, type(cancel).value.__set__, (cancel, True))
t.start()
try:
copy_file(src, dst, cancel, cbprogress=debug_progress)
except OSError as e:
print(e)
assert e.winerror == ERROR_REQUEST_ABORTED
finally:
if os.path.exists(src):
os.remove(src)
if os.path.exists(dst):
os.remove(dst)

What process is using a given file?

I'm having trouble with one of my scripts, where it erratically seems to have trouble writing to its own log, throwing the error "This file is being used by another process."
I know there are ways to handle this with try excepts, but I'd like to find out why this is happening rather than just papering over it. Nothing else should be accessing that file at all. So in order to confirm the source of the bug, I'd like to find out what service is using that file.
Is there a way in Python on Windows to check what process is using a given file?
You can use Microsoft's handle.exe command-line utility. For example:
import re
import subprocess
_handle_pat = re.compile(r'(.*?)\s+pid:\s+(\d+).*[0-9a-fA-F]+:\s+(.*)')
def open_files(name):
"""return a list of (process_name, pid, filename) tuples for
open files matching the given name."""
lines = subprocess.check_output('handle.exe "%s"' % name).splitlines()
results = (_handle_pat.match(line.decode('mbcs')) for line in lines)
return [m.groups() for m in results if m]
Note that this has limitations regarding Unicode filenames. In Python 2 subprocess passes name as an ANSI string because it calls CreateProcessA instead of CreateProcessW. In Python 3 the name gets passed as Unicode. In either case, handle.exe writes its output using a lossy ANSI encoding, so the matched filename in the result tuple may contain best-fit characters and "?" replacements.
Please don't delete this answer in case I did anything wrong but give me a chance to correct it by leaving a comment. Thanks!
There is a better way than iterating through all PIDs (as was suggested in the comments) that involves performing a Windows API call to determine all handles on a given file. Please find below a code example which I have already posted for another question (however, cannot flag as duplicate since it does not have any accepted answers). Note that this only works for Windows.
import ctypes
from ctypes import wintypes
path = r"C:\temp\stackoverflow39570207.txt"
# -----------------------------------------------------------------------------
# generic strings and constants
# -----------------------------------------------------------------------------
ntdll = ctypes.WinDLL('ntdll')
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
NTSTATUS = wintypes.LONG
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
FILE_READ_ATTRIBUTES = 0x80
FILE_SHARE_READ = 1
OPEN_EXISTING = 3
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
FILE_INFORMATION_CLASS = wintypes.ULONG
FileProcessIdsUsingFileInformation = 47
LPSECURITY_ATTRIBUTES = wintypes.LPVOID
ULONG_PTR = wintypes.WPARAM
# -----------------------------------------------------------------------------
# create handle on concerned file with dwDesiredAccess == FILE_READ_ATTRIBUTES
# -----------------------------------------------------------------------------
kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
wintypes.LPCWSTR, # In lpFileName
wintypes.DWORD, # In dwDesiredAccess
wintypes.DWORD, # In dwShareMode
LPSECURITY_ATTRIBUTES, # In_opt lpSecurityAttributes
wintypes.DWORD, # In dwCreationDisposition
wintypes.DWORD, # In dwFlagsAndAttributes
wintypes.HANDLE) # In_opt hTemplateFile
hFile = kernel32.CreateFileW(
path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, None, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, None)
if hFile == INVALID_HANDLE_VALUE:
raise ctypes.WinError(ctypes.get_last_error())
# -----------------------------------------------------------------------------
# prepare data types for system call
# -----------------------------------------------------------------------------
class IO_STATUS_BLOCK(ctypes.Structure):
class _STATUS(ctypes.Union):
_fields_ = (('Status', NTSTATUS),
('Pointer', wintypes.LPVOID))
_anonymous_ = '_Status',
_fields_ = (('_Status', _STATUS),
('Information', ULONG_PTR))
iosb = IO_STATUS_BLOCK()
class FILE_PROCESS_IDS_USING_FILE_INFORMATION(ctypes.Structure):
_fields_ = (('NumberOfProcessIdsInList', wintypes.LARGE_INTEGER),
('ProcessIdList', wintypes.LARGE_INTEGER * 64))
info = FILE_PROCESS_IDS_USING_FILE_INFORMATION()
PIO_STATUS_BLOCK = ctypes.POINTER(IO_STATUS_BLOCK)
ntdll.NtQueryInformationFile.restype = NTSTATUS
ntdll.NtQueryInformationFile.argtypes = (
wintypes.HANDLE, # In FileHandle
PIO_STATUS_BLOCK, # Out IoStatusBlock
wintypes.LPVOID, # Out FileInformation
wintypes.ULONG, # In Length
FILE_INFORMATION_CLASS) # In FileInformationClass
# -----------------------------------------------------------------------------
# system call to retrieve list of PIDs currently using the file
# -----------------------------------------------------------------------------
status = ntdll.NtQueryInformationFile(hFile, ctypes.byref(iosb),
ctypes.byref(info),
ctypes.sizeof(info),
FileProcessIdsUsingFileInformation)
pidList = info.ProcessIdList[0:info.NumberOfProcessIdsInList]
print(pidList)

How do you make an IntPtr in Python?

I've been translating a powershell script into python, mostly to learn how to do it. I've gotten stuck on these lines here:
$lpTargetHandle = [IntPtr]::Zero
$CallResult = [Kernel32]::DuplicateHandle(
$ProcessInfo.hProcess, 0x4,
[Kernel32]::GetCurrentProcess(),
[ref]$lpTargetHandle, 0, $false, 0x00000002)
echo $lpTargetHandle
This is what I have in python:
lpTargetHandle = HANDLE()
CallResult = kernel32.DuplicateHandle(ProcessInfo.hProcess, 0x4,
kernel32.GetCurrentProcess(),byref(lpTargetHandle), 0, False, 0x00000002)
print(lpTargetHandle)
Here is the output I am getting:
>>> lpTargetHandle = HANDLE()
>>> CallResult = kernel32.DuplicateHandle(ProcessInfo.hProcess, 0x4, kernel32.GetCurrentProcess(),byref(lpTargetHandle), 0, False, 0x00000002)
>>>
>>> print(lpTargetHandle)
c_void_p(None)
>>> lpTargetHandle.value
>>> type(lpTargetHandle.value)
<type 'NoneType'>
What is supposed to happen, is the lpTargetHandle pointer should return back the Thread ID number, but I'm just getting Nones. I've seen that IntPtr's are handled in IronPython, but my goal is to learn vanilla python. My includes are:
from ctypes import *
from ctypes.wintypes import *
How do you duplicate an IntPtr in normal Python (CPython)?
Specifically, how do you write $var = [IntPtr]::Zero in python?
I've also tried this, but it did not work:
tid = POINTER(c_int)
num = c_int(0)
addr = addressof(num)
ptr = cast(addr,tid)
CallResult = = kernel32.DuplicateHandle(ProcessInfo.hProcess, 0x4,
kernel32.GetCurrentProcess(),ptr, 0, False, 0x00000002)
Here is a pastebin of the full python code I have
Here is a pastebin of the powershell function I am working on duplicating.
Edit: Here is the relevant function that I am trying to duplicate in C
HANDLE hThread = nullptr;
DuplicateHandle(procInfo.hProcess, (HANDLE)0x4,
GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
return hThread;
According to the Windows documentation, this is the function prototype:
BOOL WINAPI DuplicateHandle(
_In_ HANDLE hSourceProcessHandle,
_In_ HANDLE hSourceHandle,
_In_ HANDLE hTargetProcessHandle,
_Out_ LPHANDLE lpTargetHandle,
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwOptions
);
The equivalent in python for the LPHANDLE type would be wintypes.LPHANDLE

Python - ctypes and mutable buffers

I'm trying to work with ctypes, and I can't get the call to FormatMessage() to work properly.
Here's the code I have so far; I think the only issue is passing in a mutable buffer; I'm getting an ArgumentError from ctypes about lpBuffer
import ctypes
from ctypes.wintypes import DWORD
def main():
fm = ctypes.windll.kernel32.FormatMessageA
fm.argtypes = [DWORD,DWORD,DWORD,DWORD,ctypes.wintypes.LPWSTR(),DWORD]
dwFlags = DWORD(0x1000) # FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM
lpSource = DWORD(0)
dwMessageId = DWORD(0x05)
dwLanguageId = DWORD(0)
#buf = ctypes.wintypes.LPWSTR()
#lpBuffer = ctypes.byref(buf)
lpBuffer = ctypes.create_string_buffer(512)
nSize = DWORD(512)
res = fm(dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize)
print res
I'm getting an error on the lpBuffer argument saying it's a wrong type, but I've tried as many variations of passing in the buffer as I could think of. I've tried doing it similar to here: https://gist.github.com/CBWhiz/6135237 and setting FORMAT_MESSAGE_ALLOCATE_BUFFER then passing in a LPWSTR() byref, I've also tried changing the argtype, pointer and casting to a variety of LPWSTR(), c_char_p, etc, but no matter what I do it keeps complaining.
What's the proper syntax to get the function to execute properly? I know ctypes can be finnicky but I haven't found anything in the documentation to resolve the issue (I know the documentation uses prototype() but I'd like to do it this way for now)
Thanks
Here's the argtypes definition for FormatMessageW (note "W" for Unicode):
import ctypes
from ctypes import wintypes
fm = ctypes.windll.kernel32.FormatMessageW
fm.argtypes = [
wintypes.DWORD, # dwFlags
wintypes.LPCVOID, # lpSource
wintypes.DWORD, # dwMessageId
wintypes.DWORD, # dwLanguageId
wintypes.LPWSTR, # lpBuffer
wintypes.DWORD, # nSize
wintypes.LPVOID, # Arguments (va_list *)
]
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100
FORMAT_MESSAGE_FROM_SYSTEM = 0x1000
If FormatMessage allocates the buffer, you have to instead pass a reference to lpBuffer. Just cast the reference to get around the TypeError. Also, remember to call kernel32.LocalFree to free the buffer:
def main():
dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
lpSource = None
dwMessageId = 5
dwLanguageId = 0
lpBuffer = wintypes.LPWSTR()
nSize = 0 # minimum size
Arguments = None
if not fm(dwFlags, lpSource, dwMessageId, dwLanguageId,
ctypes.cast(ctypes.byref(lpBuffer), wintypes.LPWSTR),
nSize, Arguments):
raise ctypes.WinError()
msg = lpBuffer.value.rstrip()
ctypes.windll.kernel32.LocalFree(lpBuffer)
return msg

Convert C# P/Invoke code to Python ctypes?

I'm having problem converting this C# code to python using ctypes. This code is for hiding windows 7 start orb. Here's the link.
[DllImport("user32.dll")]
private static extern IntPtr FindWindowEx(
IntPtr parentHwnd,
IntPtr childAfterHwnd,
IntPtr className,
string windowText);
IntPtr hwndOrb = FindWindowEx(IntPtr.Zero, IntPtr.Zero, (IntPtr)0xC017, null);
do i have to define
FindWindow = ctypes.windll.user32.FindWindowEx
FindWindow.restype = wintypes.HWND
FindWindow.argtypes = [
wintypes.HWND, ##hWnd
wintypes.HWND, ##hWnd
]
Or just use it directly? Sorry I'm new in using python ctypes.
hWnd = win32gui.FindWindowEx (win32gui.GetDesktopWindow(),
None,0xC017 ,None)
It'd be helpful to have the error message you're seeing. However, this is almost certainly because you need to use user32.FindWindowExW (or user32.FindWindowExA if you really want the ASCII, non-Unicode version) rather than straight FindWindowEx. You also need to specify argtypes for all four parameters.
Here's the prototype from the docs:
HWND WINAPI FindWindowEx(
_In_opt_ HWND hwndParent,
_In_opt_ HWND hwndChildAfter,
_In_opt_ LPCTSTR lpszClass,
_In_opt_ LPCTSTR lpszWindow
);
So what about this?
FindWindowEx = ctypes.windll.user32.FindWindowExW
FindWindowEx.argtypes = [
wintypes.HWND,
wintypes.HWND,
wintypes.LPCWSTR,
wintypes.LPCWSTR,
]
FindWindowEx.restype = wintypes.HWND
You can also do FindWindow (rather than FindWindowEx) as per the C# code you linked to:
>>> FindWindow = ctypes.windll.user32.FindWindowW
>>> FindWindow.argtypes = [wintypes.LPCWSTR, wintypes.LPCWSTR]
>>> FindWindow.restype = wintypes.HWND
>>> FindWindow('Shell_TrayWnd', '')
65670L

Categories

Resources