[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