0

I need to access all memory of a running process in my local Windows 7-64bit. I am new to winapi.

Here is my problem; Whenever I try to Open a process and reads its memory, I get Access is Denied error.

I searched and found something. It is said that If I run the main process as Administrator and use PROCESS_ALL_ACCESS on OpenProcess, I would have enough right to do it as it is said. OK, I did it. but nothing is changed. On reading memory, I still get Access is Denied.

So, I kept searching and found another thing which is enabling SeDebugPrivilege. I have also done that but nothing is changed. I still get the error.

I've read the quest and his answer here; Windows Vista/Win7 Privilege Problem: SeDebugPrivilege & OpenProcess . But as I said, I am really new to winapi. I could not solve my problem yet. Is there anything which which I need to configure in my local operating system?

Here is my Python code with pywin32;

from _ctypes import byref, sizeof, Structure
from ctypes import windll, WinError, c_buffer, c_void_p, create_string_buffer
from ctypes.wintypes import *
import win32security
import win32api
import gc
import ntsecuritycon
from struct import Struct
from win32con import PROCESS_ALL_ACCESS
from struct import calcsize

MEMORY_STATES = {0x1000: "MEM_COMMIT", 0x10000: "MEM_FREE", 0x2000: "MEM_RESERVE"}
MEMORY_PROTECTIONS = {0x10: "PAGE_EXECUTE", 0x20: "PAGE_EXECUTE_READ", 0x40: "PAGEEXECUTE_READWRITE",
                      0x80: "PAGE_EXECUTE_WRITECOPY", 0x01: "PAGE_NOACCESS", 0x04: "PAGE_READWRITE",
                      0x08: "PAGE_WRITECOPY"}
MEMORY_TYPES = {0x1000000: "MEM_IMAGE", 0x40000: "MEM_MAPPED", 0x20000: "MEM_PRIVATE"}


class MEMORY_BASIC_INFORMATION(Structure):
    _fields_ = [
        ("BaseAddress", c_void_p),
        ("AllocationBase", c_void_p),
        ("AllocationProtect", DWORD),
        ("RegionSize", UINT),
        ("State", DWORD),
        ("Protect", DWORD),
        ("Type", DWORD)
    ]


class SYSTEM_INFO(Structure):
    _fields_ = [("wProcessorArchitecture", WORD),
                ("wReserved", WORD),
                ("dwPageSize", DWORD),
                ("lpMinimumApplicationAddress", DWORD),
                ("lpMaximumApplicationAddress", DWORD),
                ("dwActiveProcessorMask", DWORD),
                ("dwNumberOfProcessors", DWORD),
                ("dwProcessorType", DWORD),
                ("dwAllocationGranularity", DWORD),
                ("wProcessorLevel", WORD),
                ("wProcessorRevision", WORD)]


class PyMEMORY_BASIC_INFORMATION:
    def __init__(self, MBI):
        self.MBI = MBI
        self.set_attributes()


    def set_attributes(self):
        self.BaseAddress = self.MBI.BaseAddress
        self.AllocationBase = self.MBI.AllocationBase
        self.AllocationProtect = MEMORY_PROTECTIONS.get(self.MBI.AllocationProtect, self.MBI.AllocationProtect)
        self.RegionSize = self.MBI.RegionSize
        self.State = MEMORY_STATES.get(self.MBI.State, self.MBI.State)
        # self.Protect = self.MBI.Protect  # uncomment this and comment next line if you want to do a bitwise check on Protect.
        self.Protect = MEMORY_PROTECTIONS.get(self.MBI.Protect, self.MBI.Protect)
        self.Type = MEMORY_TYPES.get(self.MBI.Type, self.MBI.Type)


ASSUME_ALIGNMENT = True


class TARGET:
    """Given a ctype (initialized or not) this coordinates all the information needed to read, write and compare."""

    def __init__(self, ctype):

        self.alignment = 1
        self.ctype = ctype
        # size of target data
        self.size = sizeof(ctype)
        self.type = ctype._type_

        # get the format type needed for struct.unpack/pack.
        while hasattr(self.type, "_type_"):
            self.type = self.type._type_
            # string_buffers and char arrays have _type_ 'c'
            # but that makes it slightly slower to unpack
            # so swap is for 's'.
        if self.type == "c":
            self.type = "s"
        # calculate byte alignment. this speeds up scanning substantially
        # because we can read and compare every alignment bytes
        # instead of every single byte.
        # although if we are scanning for a string the alignment is defaulted to 1 \
        # (im not sure if this is correct).
        elif ASSUME_ALIGNMENT:
            # calc alignment
            divider = 1
            for i in xrange(4):
                divider *= 2
                if not self.size % divider:
                    self.alignment = divider

        # size of target ctype.
        self.type_size = calcsize(self.type)
        # length of target / array length.
        self.length = self.size / self.type_size
        self.value = getattr(ctype, "raw", ctype.value)
        # the format string used for struct.pack/unpack.
        self.format = str(self.length) + self.type
        # efficient packer / unpacker for our own format.
        self.packer = Struct(self.format)


    def get_packed(self):

        """Gets the byte representation of the ctype value for use with WriteProcessMemory."""
        return self.packer.pack(self.value)


    def __str__(self):
        return str(self.ctype)[:10] + "..." + " <" + str(self.value)[:10] + "..." + ">"


class Memory(object):
    def __init__(self, process_handle, target):
        self._process_handle = process_handle
        self._target = target
        self.found = []
        self.__scann_process()


    def __scann_process(self):
        """scans a processes pages for the target value."""

        si = SYSTEM_INFO()
        psi = byref(si)
        windll.kernel32.GetSystemInfo(psi)

        base_address = si.lpMinimumApplicationAddress
        max_address = si.lpMaximumApplicationAddress

        page_address = base_address

        while page_address < max_address:
            page_address = self.__scan_page(page_address)

            if len(self.found) >= 60000000:
                print("[Warning] Scan ended early because too many addresses were found to hold the target data.")
                break

        gc.collect()
        return self.found


    def __scan_page(self, page_address):
        """Scans the entire page for TARGET instance and returns the next page address and found addresses."""

        information = self.VirtualQueryEx(page_address)
        base_address = information.BaseAddress
        region_size = information.RegionSize
        next_region = base_address + region_size
        size = self._target.size
        target_value = self._target.value
        step = self._target.alignment
        unpacker = self._target.packer.unpack

        if information.Type != "MEM_PRIVATE" or \
                        region_size < size or \
                        information.State != "MEM_COMMIT" or \
                        information.Protect not in ["PAGE_EXECUTE_READ", "PAGEEXECUTE_READWRITE", "PAGE_READWRITE"]:
            return next_region

        page_bytes = self.ReadMemory(base_address, region_size)

        for i in xrange(0, (region_size - size), step):

            partial = page_bytes[i:i + size]

            if unpacker(partial)[0] == target_value:
                self.found.append(base_address + i)

        del page_bytes  # free the buffer
        return next_region

    def ReadMemory(self, address, size):
        cbuffer = c_buffer(size)
        success = windll.kernel32.ReadProcessMemory(
            self._process_handle,
            address,
            cbuffer,
            size,
            0)

        assert success, "ReadMemory Failed with success == %s and address == %s and size == %s.\n%s" % (
            success, address, size, WinError(win32api.GetLastError()))
        return cbuffer.raw


    def VirtualQueryEx(self, address):
        MBI = MEMORY_BASIC_INFORMATION()
        MBI_pointer = byref(MBI)
        size = sizeof(MBI)
        success = windll.kernel32.VirtualQueryEx(
            self._process_handle,
            address,
            MBI_pointer,
            size)

        assert success, "VirtualQueryEx Failed with success == %s.\n%s" % (
            success, WinError(win32api.GetLastError())[1])
        assert success == size, "VirtualQueryEx Failed because not all data was written."
        return PyMEMORY_BASIC_INFORMATION(MBI)


def AdjustPrivilege(priv):
    flags = win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY
    p = win32api.GetCurrentProcess()
    htoken = win32security.OpenProcessToken(p, flags)
    id = win32security.LookupPrivilegeValue(None, priv)
    newPrivileges = [(id, win32security.SE_PRIVILEGE_ENABLED)]
    win32security.AdjustTokenPrivileges(htoken, 0, newPrivileges)
    win32api.CloseHandle(htoken)


def OpenProcess(pid=win32api.GetCurrentProcessId()):
    # ntsecuritycon.SE_DEBUG_NAME = "SeDebugPrivilege"
    AdjustPrivilege(ntsecuritycon.SE_DEBUG_NAME)

    phandle = windll.kernel32.OpenProcess( \
        PROCESS_ALL_ACCESS,
        0,
        pid)

    assert phandle, "Failed to open process!\n%s" % WinError(win32api.GetLastError())[1]
    return phandle


PID = 22852
process_handle = OpenProcess(PID)
Memory(process_handle, TARGET(create_string_buffer("1456")))

Here is the error I always get;

AssertionError: ReadMemory Failed with success == 0 and address == 131072 and size == 4096.
[Error 5] Access is denied.

I do not know what information else about my code and my personal Windows 7 operating system, I should provide to you. If you need to know more, please ask it from me, I will provide it to solve that problem.

I guess, this is about a lack of configuration in my operating system , not about pywin32. I'll be waiting for your solutions.

Community
  • 1
  • 1
Ahmet DAL
  • 4,445
  • 9
  • 47
  • 71
  • Lesson 1 for Windows API programming: Check for errors. [AdjustTokenPrivileges](http://msdn.microsoft.com/en-us/library/windows/desktop/aa375202.aspx) has a return value that should not be silently ignored. – IInspectable Jan 11 '15 at 22:39
  • @IInspectable: actually it's even worse than that; AdjustTokenPrivileges is one of the very few functions where you need to check the last-error code even if the return code indicated success. (But if that was the problem, OpenProcess would have failed, not ReadMemory.) – Harry Johnston Jan 12 '15 at 03:52
  • Are you sure than 131072 is a valid address in the target process? – Harry Johnston Jan 12 '15 at 03:55
  • @IInspectable, thank you for the lesson. I'll be looking for it. But there is no problem right there. – Ahmet DAL Jan 12 '15 at 23:10
  • I commented late. I was trying to edit my code to show you by cutting inproper parts. @HarryJohnston, please see my edited code. Actualy, I was not who is giving that address(131072) directly. I wanted to scan and search all memory cells of a processes. This codes is creating VirtualQueryEx for all addreses between system minimum and maximum adresses. While it is walking on addreses and firstly it realize an address(131072) is needed to be Read(ReadProcessMemory), I get the error. I guess, the addres is valid. – Ahmet DAL Jan 12 '15 at 23:12

0 Answers0