I'm trying to implement a memory scanner in python. The problem is, it's too slow. What it does it gets a number from the command line and compares it to every address, then writes it to an output file. How can I improve my algorithm?

import ctypes as c
from ctypes import wintypes as w
from struct import *
from time import *
import datetime
import sys

pid = 1234

k32 = c.windll.kernel32

OpenProcess = k32.OpenProcess
OpenProcess.argtypes = [w.DWORD,w.BOOL,w.DWORD]
OpenProcess.restype = w.HANDLE

ReadProcessMemory = k32.ReadProcessMemory
ReadProcessMemory.argtypes = [w.HANDLE,w.LPCVOID,w.LPVOID,c.c_size_t,c.POINTER(c.c_size_t)]
ReadProcessMemory.restype = w.BOOL
PAA = 0x1F0FFF
address = 0x4000000
ph = OpenProcess(PAA,False,int(pid)) #program handle

buff = c.create_string_buffer(4)
bufferSize = (c.sizeof(buff))
bytesRead = c.c_ulonglong(0)

addresses_list = xrange(address,0x9000000,0x4)
for i in addresses_list:
    ReadProcessMemory(ph, c.c_void_p(i), buff, bufferSize, c.byref(bytesRead))
    value = unpack('I',buff)[0]
    if value == int(sys.argv[1]):
        log.write('%x\r\n' % (i, ))
  • \$\begingroup\$ One obvious improvement would be to make it actually work. To do this, you need to suspend all threads in the target (shall I say "victim"?) process. Otherwise you keep chasing a moving target. Once that's done you can think about making it fast. \$\endgroup\$ – IInspectable Feb 12 '16 at 21:27
  • \$\begingroup\$ The addresses won't change, I can control it, or at least tell when it changes. \$\endgroup\$ – Lior Feb 12 '16 at 21:28
  • \$\begingroup\$ Memory is constantly in flux in a running process. Memory contents constantly change. Unless you suspend the entire process, there's not even a guarantee that if you find your designated value, that it's still there when you come around to do something useful (e.g. cheat) with it. \$\endgroup\$ – IInspectable Feb 12 '16 at 22:32
  • \$\begingroup\$ I'm guessing you are looking for a malware marker or similar. If that's true, maybe your input data can be designed to better characterize where the marker appears. Does it only appear in executable images? On a particular heap? On a stack (of a particular thread)? If so you can significantly reduce the amount of memory you need to scan. FWIW, there are security companies that provide software that does this along with the service that tells the software what to scan for (based on current threats) \$\endgroup\$ – Χpẘ Feb 17 '16 at 18:55
  • You should check if ReadProcessMemory fails (returns 0)
  • parse sys.argv only once
  • read bigger chunks of memory in a row into an efficient array
  • best use numpy for search (or at least array.array)

Key lines using numpy:

import numpy as np

match_val = int(sys.argv[1])
a = np.zeros(4096, 'l')     # chunk size; should be even bigger ..
r = ReadProcessMemory(ph, chunk_start_adr, a.ctypes.data, 
                      a.itemsize * a.size, c.byref(bytesRead))
if r:
    indices, = np.where(a == match_val)   # fast bulk search
    log.write(''.join('%x\r\n' % i for i in indices))

It will be lightning fast.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.