[python-win32] Quest for memory scanner
Michael C
mysecretrobotfactory at gmail.com
Fri Oct 20 15:54:24 EDT 2017
Hello Tim, everyone:
I actually have a semi-working scanner, but I can't figure out why it
doesn't return
nearly as many addresses as Cheat Engine does.(for scan run #1) Let's say
I am scanning the Calculator that comes with Windows.
Please have a look!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-win32/attachments/20171020/1941ec41/attachment-0001.html>
-------------- next part --------------
import ctypes
from ctypes.wintypes import WORD, DWORD, LPVOID
import psutil
import sys
def main():
PID = int(input('enter PID'))
target_value = int(input('new scan value'))
# a simple list to contain all the addresses the code finds.
hit_pool = list()
# calls the function to scan the application's memory, and then returns
# the addresses found to contain the target value, back into the list.
hit_pool = First_scan(hit_pool, target_value, PID)
# prints all the addresses to take a look.
print(hit_pool)
# calls the second scan function by passing it the hit_pool, and then
# scan for the value present in the address, compare it with the new
# target value, if they are differnt, the address is removed.
while target_value != -999:
target_value = int(input('new scan value'))
hit_pool = Second_scan(hit_pool, target_value, PID)
print('done.')
##print(hit_pool)
def First_scan(hit_pool, target_value, PID):
###############################################################
###############################################################
###############################################################
## I think this part works properly!
###############################################################
###############################################################
PVOID = LPVOID
SIZE_T = ctypes.c_size_t
# https://msdn.microsoft.com/en-us/library/aa383751#DWORD_PTR
if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulonglong):
DWORD_PTR = ctypes.c_ulonglong
elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulong):
DWORD_PTR = ctypes.c_ulong
class SYSTEM_INFO(ctypes.Structure):
"""https://msdn.microsoft.com/en-us/library/ms724958"""
class _U(ctypes.Union):
class _S(ctypes.Structure):
_fields_ = (('wProcessorArchitecture', WORD),
('wReserved', WORD))
_fields_ = (('dwOemId', DWORD), # obsolete
('_s', _S))
_anonymous_ = ('_s',)
_fields_ = (('_u', _U),
('dwPageSize', DWORD),
('lpMinimumApplicationAddress', LPVOID),
('lpMaximumApplicationAddress', LPVOID),
('dwActiveProcessorMask', DWORD_PTR),
('dwNumberOfProcessors', DWORD),
('dwProcessorType', DWORD),
('dwAllocationGranularity', DWORD),
('wProcessorLevel', WORD),
('wProcessorRevision', WORD))
_anonymous_ = ('_u',)
LPSYSTEM_INFO = ctypes.POINTER(SYSTEM_INFO)
Kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
Kernel32.GetSystemInfo.restype = None
Kernel32.GetSystemInfo.argtypes = (LPSYSTEM_INFO,)
sysinfo = SYSTEM_INFO()
Kernel32.GetSystemInfo(ctypes.byref(sysinfo))
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
Process = Kernel32.OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, False, PID)
print('process:', Process)
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
"""https://msdn.microsoft.com/en-us/library/aa366775"""
_fields_ = (('BaseAddress', PVOID),
('AllocationBase', PVOID),
('AllocationProtect', DWORD),
('RegionSize', SIZE_T),
('State', DWORD),
('Protect', DWORD),
('Type', DWORD))
mbi = MEMORY_BASIC_INFORMATION()
print('VirtualQueryEx ran properly?',Kernel32.VirtualQueryEx(Process, \
sysinfo.lpMinimumApplicationAddress, ctypes.byref(mbi),ctypes.sizeof(mbi)))
###############################################################
###############################################################
###############################################################
## I think the following part has a bug
###############################################################
###############################################################
ReadProcessMemory = Kernel32.ReadProcessMemory
##
MEM_COMMIT = 0x00001000;
PAGE_READWRITE = 0x04;
#######
#######
#######
####### IMPORTANT! I know I am supposed to initiate buffer
####### with something, but I can't work out what to put
####### down!
buffer = ctypes.c_double()
nread = SIZE_T()
#######
#######
#######
#######
##start = ctypes.c_void_p(mbi.BaseAddress)
current_address = sysinfo.lpMinimumApplicationAddress
end_address = sysinfo.lpMaximumApplicationAddress
#######
#######
#######
####### This is where the real memory scanning happens!
# this variable keeps track of how many addresses have been found!
hit_count = 0
while current_address < end_address:
#### this line figures out if this chunk of memory can be scanned!
Kernel32.VirtualQueryEx(Process, \
current_address, ctypes.byref(mbi),ctypes.sizeof(mbi))
#### this line figures out if this chunk of memory can be scanned!
if mbi.Protect == PAGE_READWRITE and mbi.State == MEM_COMMIT :
print('This region can be scanned!')
index = current_address
end = current_address + mbi.RegionSize - 7
#### finally, the scanning part!
for address in range(index, end, 1):
if ReadProcessMemory(Process, address, ctypes.byref(buffer), \
ctypes.sizeof(buffer), ctypes.byref(nread)):
#### compares the values to the target value
#### I haven't worked out how to 'round'
if buffer.value < (target_value + 1) and \
buffer.value > (target_value - 1):
print(buffer, buffer.value, address, 'hit:',
hit_count)
hit_count += 1
#### add the address to the list!
hit_pool.append(i)
else:
print('else happend.')
input('program pause because ReadProcessMemory happened.')
current_address += mbi.RegionSize
print(hit_count)
return hit_pool
def Second_scan(hit_pool, target_value, PID):
###############################################################
###############################################################
###############################################################
## I think this part works properly!
###############################################################
###############################################################
PVOID = LPVOID
SIZE_T = ctypes.c_size_t
# https://msdn.microsoft.com/en-us/library/aa383751#DWORD_PTR
if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulonglong):
DWORD_PTR = ctypes.c_ulonglong
elif ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulong):
DWORD_PTR = ctypes.c_ulong
class SYSTEM_INFO(ctypes.Structure):
"""https://msdn.microsoft.com/en-us/library/ms724958"""
class _U(ctypes.Union):
class _S(ctypes.Structure):
_fields_ = (('wProcessorArchitecture', WORD),
('wReserved', WORD))
_fields_ = (('dwOemId', DWORD), # obsolete
('_s', _S))
_anonymous_ = ('_s',)
_fields_ = (('_u', _U),
('dwPageSize', DWORD),
('lpMinimumApplicationAddress', LPVOID),
('lpMaximumApplicationAddress', LPVOID),
('dwActiveProcessorMask', DWORD_PTR),
('dwNumberOfProcessors', DWORD),
('dwProcessorType', DWORD),
('dwAllocationGranularity', DWORD),
('wProcessorLevel', WORD),
('wProcessorRevision', WORD))
_anonymous_ = ('_u',)
LPSYSTEM_INFO = ctypes.POINTER(SYSTEM_INFO)
Kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
Kernel32.GetSystemInfo.restype = None
Kernel32.GetSystemInfo.argtypes = (LPSYSTEM_INFO,)
sysinfo = SYSTEM_INFO()
Kernel32.GetSystemInfo(ctypes.byref(sysinfo))
PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ = 0x0010
Process = Kernel32.OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, False, PID)
print('process:', Process)
class MEMORY_BASIC_INFORMATION(ctypes.Structure):
"""https://msdn.microsoft.com/en-us/library/aa366775"""
_fields_ = (('BaseAddress', PVOID),
('AllocationBase', PVOID),
('AllocationProtect', DWORD),
('RegionSize', SIZE_T),
('State', DWORD),
('Protect', DWORD),
('Type', DWORD))
mbi = MEMORY_BASIC_INFORMATION()
print('VirtualQueryEx ran properly?',Kernel32.VirtualQueryEx(Process, \
sysinfo.lpMinimumApplicationAddress, ctypes.byref(mbi),ctypes.sizeof(mbi)))
###############################################################
###############################################################
###############################################################
## I think the following part has a bug
###############################################################
###############################################################
ReadProcessMemory = Kernel32.ReadProcessMemory
MEM_COMMIT = 0x00001000;
PAGE_READWRITE = 0x04;
#######
#######
#######
####### IMPORTANT! I know I am supposed to initiate buffer
####### with something, but I can't work out what to put
####### down!
buffer = ctypes.c_double()
nread = SIZE_T()
#######
#######
#######
#######
hit_count = 0
hit_pool_2 = list()
for address in hit_pool:
Kernel32.VirtualQueryEx(Process, \
address, ctypes.byref(mbi),ctypes.sizeof(mbi))
if mbi.Protect == PAGE_READWRITE and mbi.State == MEM_COMMIT :
print('This region can be scanned!')
if ReadProcessMemory(Process, address, ctypes.byref(buffer), \
ctypes.sizeof(buffer), ctypes.byref(nread)):
if buffer.value < (target_value + 1) and \
buffer.value > (target_value - 1):
print(i,'OVERKILL!!!')
hit_pool_2.append(address)
else:
print('else happend.')
input('program pause because ReadProcessMemory happened.')
else:
'2nd run VirtualQueryEx error'
hit_pool = hit_pool_2
print('Hit_pool', hit_pool)
return hit_pool_2
main()
More information about the python-win32
mailing list