Python Ctypes Read/WriteProcessMemory() - Error 5/998 Help!

1

Please don't get scared but the following code, if you are familiar with ctypes or C it should be easy to read.

I have been trying to get my ReadProcessMemory() and WriteProcessMemory() functions to be working for so long and have tried almost every possibility but the right one.

It launches the target program, returns its PID and handle just fine. But I always get a error code of 5 - ERROR_ACCESS_DENIED. When I run the read function(forget the write for now). I am launching this program as what I believe to be a CHILD process with PROCESS_ALL_ACCESS or CREATE_PRESERVE_CODE_AUTHZ_LEVEL.

I have also tried PROCESS_ALL_ACCESS and PROCESS_VM_READ when I open the handle.

I can also say that it is a valid memory location because I can find it on the running program with CheatEngine.

As for VirtualQuery() I get an error code of 998 - ERROR_NOACCESS which further confirms my suspicion of it being some security/privilege problem.

Any help or ideas would be very appreciated, again, it's my whole program so far, don't let it scare you =P.

from ctypes import *
from ctypes.wintypes import BOOL
import binascii


BYTE      = c_ubyte
WORD      = c_ushort
DWORD     = c_ulong
LPBYTE    = POINTER(c_ubyte)
LPTSTR    = POINTER(c_char) 
HANDLE    = c_void_p
PVOID     = c_void_p
LPVOID    = c_void_p
UNIT_PTR  = c_ulong
SIZE_T    = c_ulong

class STARTUPINFO(Structure):
    _fields_ = [("cb",            DWORD),        
                ("lpReserved",    LPTSTR), 
                ("lpDesktop",     LPTSTR),  
                ("lpTitle",       LPTSTR),
                ("dwX",           DWORD),
                ("dwY",           DWORD),
                ("dwXSize",       DWORD),
                ("dwYSize",       DWORD),
                ("dwXCountChars", DWORD),
                ("dwYCountChars", DWORD),
                ("dwFillAttribute",DWORD),
                ("dwFlags",       DWORD),
                ("wShowWindow",   WORD),
                ("cbReserved2",   WORD),
                ("lpReserved2",   LPBYTE),
                ("hStdInput",     HANDLE),
                ("hStdOutput",    HANDLE),
                ("hStdError",     HANDLE),]

class PROCESS_INFORMATION(Structure):
    _fields_ = [("hProcess",    HANDLE),
                ("hThread",     HANDLE),
                ("dwProcessId", DWORD),
                ("dwThreadId",  DWORD),]

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

class SECURITY_ATTRIBUTES(Structure):
    _fields_ = [("Length", DWORD),
                ("SecDescriptor", LPVOID),
                ("InheritHandle", BOOL)]

class Main():
    def __init__(self):
        self.h_process = None
        self.pid = None

    def launch(self, path_to_exe):
        CREATE_NEW_CONSOLE = 0x00000010
        CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000

        startupinfo = STARTUPINFO()
        process_information = PROCESS_INFORMATION()
        security_attributes = SECURITY_ATTRIBUTES()

        startupinfo.dwFlags = 0x1
        startupinfo.wShowWindow = 0x0


        startupinfo.cb = sizeof(startupinfo)
        security_attributes.Length = sizeof(security_attributes)
        security_attributes.SecDescriptior = None
        security_attributes.InheritHandle = True

        if windll.kernel32.CreateProcessA(path_to_exe,
                                   None,
                                   byref(security_attributes),
                                   byref(security_attributes),
                                   True,
                                   CREATE_PRESERVE_CODE_AUTHZ_LEVEL,
                                   None,
                                   None,
                                   byref(startupinfo),
                                   byref(process_information)):

            self.pid = process_information.dwProcessId
            print "Success: CreateProcess - ", path_to_exe
        else:
            print "Failed: Create Process - Error code: ", windll.kernel32.GetLastError()

    def get_handle(self, pid):
        PROCESS_ALL_ACCESS = 0x001F0FFF
        PROCESS_VM_READ = 0x0010
        self.h_process = windll.kernel32.OpenProcess(PROCESS_VM_READ, False, pid)
        if self.h_process:
            print "Success: Got Handle - PID:", self.pid
        else:
            print "Failed: Get Handle - Error code: ", windll.kernel32.GetLastError()
            windll.kernel32.SetLastError(10000)

    def read_memory(self, address):
        buffer = c_char_p("The data goes here")
        bufferSize = len(buffer.value)
        bytesRead = c_ulong(0)
        if windll.kernel32.ReadProcessMemory(self.h_process, address, buffer, bufferSize, byref(bytesRead)):
            print "Success: Read Memory - ", buffer.value
        else:
            print "Failed: Read Memory - Error Code: ", windll.kernel32.GetLastError()
            windll.kernel32.CloseHandle(self.h_process)
            windll.kernel32.SetLastError(10000)

    def write_memory(self, address, data):
        count = c_ulong(0)
        length = len(data)
        c_data = c_char_p(data[count.value:])
        null = c_int(0)
        if not windll.kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
            print  "Failed: Write Memory - Error Code: ", windll.kernel32.GetLastError()
            windll.kernel32.SetLastError(10000)
        else:
            return False

    def virtual_query(self, address):
        basic_memory_info = MEMORY_BASIC_INFORMATION()
        windll.kernel32.SetLastError(10000)
        result = windll.kernel32.VirtualQuery(address, byref(basic_memory_info), byref(basic_memory_info))
        if result:
            return True
        else:
            print  "Failed: Virtual Query - Error Code: ", windll.kernel32.GetLastError()


main = Main()
address = None
main.launch("C:\Program Files\ProgramFolder\Program.exe")
main.get_handle(main.pid)
#main.write_memory(address, "\x61")
while 1:
    print '1 to enter an address'
    print '2 to virtual query address'
    print '3 to read address'
    choice = raw_input('Choice: ')
    if choice == '1':
        address = raw_input('Enter and address: ')
    if choice == '2':
        main.virtual_query(address)
    if choice == '3':
        main.read_memory(address)

Thanks!

python
ctypes
readprocessmemory
asked on Stack Overflow Mar 23, 2010 by (unknown user)

5 Answers

2

You should try to set debugging privileges to your process. Use the following code once before you try to Open / Create a process.

class TOKEN_PRIVILEGES( Structure ):
    _fields_ = [
            ('PrivilegeCount',  c_uint),
            ('Luid',            LUID),
            ('Attributes',      c_uint) ]

OpenProcessToken = windll.advapi32.OpenProcessToken
OpenProcessToken.argtypes = [
    c_int,      # HANDLE ProcessHandle
    c_uint,     # DWORD DesiredAccess
    c_void_p ]  # PHANDLE TokenHandle
OpenProcessToken.restype = ErrorIfZero

AdjustTokenPrivileges = windll.advapi32.AdjustTokenPrivileges
AdjustTokenPrivileges.argtypes = [
    c_int,      # HANDLE TokenHandle
    c_int,      # BOOL DisableAllPrivileges
    c_void_p,   # PTOKEN_PRIVILEGES NewState
    c_uint,     # DWORD BufferLength
    c_void_p,   # PTOKEN_PRIVILEGES PreviousState
    c_void_p ]  # PDWORD ReturnLength
AdjustTokenPrivileges.restype = ErrorIfZero

LookupPrivilegeValue = windll.advapi32.LookupPrivilegeValueA
LookupPrivilegeValue.argtypes = [
c_char_p,   # LPCTSTR lpSystemName
c_char_p,   # LPCTSTR lpName
c_void_p ]  # PLUID lpLuid
LookupPrivilegeValue.restype = ErrorIfZero

access_token = c_int(0)
privileges = TOKEN_PRIVILEGES()

OpenProcessToken( GetCurrentProcess(), win32con.TOKEN_QUERY | win32con.TOKEN_ADJUST_PRIVILEGES, byref(access_token) )
access_token = access_token.value
LookupPrivilegeValue( None, "SeDebugPrivilege", byref(privileges.Luid) )
privileges.PrivilegeCount = 1
privileges.Attributes = 2
AdjustTokenPrivileges(
        access_token,
        0,
        byref(privileges),
        0,
        None,
        None )
CloseHandle( access_token )
answered on Stack Overflow Mar 11, 2011 by Pagefault
1

Maybe this will help you: Creating a Security Descriptor for a New Object in C++

answered on Stack Overflow Jun 5, 2010 by sbelieve • edited Aug 26, 2011 by Jérôme Verstrynge
0

One possible reason for your access denied error is that the user under which you run WriteProcessMemory runs needs to have DEBUG privilege.

Starting with Vista, this privilege is only activated for Administrators, and only when running the application with "Run as Admin".

You can add the privilege to any account.

answered on Stack Overflow Apr 3, 2010 by Meh
0

I see several problems with your code, and it's difficult to know which one is the underlying cause of your exact problem. For example, the line:

address = raw_input('Enter and address: ')

Should probably be something like:

address = long(raw_input('Enter and address: '), 0)

As the code stands, every time you pass address to a function via ctypes what you are actually doing is creating a temporary buffer which contains exactly the string typed by the user and passing in the address of that buffer in the Python process. Definitely not what you want. If I fix that issue, then your program seems to work most of the time.

From my limited testing, most (all?) of the rest of the failures can be fixed by setting the correct argtypes for ReadProcessMemory. This is the single biggest issue I see with ctypes code, a problem exacerbated by handling ctypes.c_voidp as int in Python. If argtypes is not specified, then all arguments are considered to be ctypes.c_int. Anything outside of the range of signed integer -- a pointer or handle with high bit set, for example -- is silently truncated.

Not the cause of your bugs but suboptimal are the lines:

buffer = c_char_p("The data goes here")
bufferSize = len(buffer.value)

The ctypes module provides functions for creating buffers:

bufferSize = 32
buffer = ctypes.create_string_buffer(bufferSize)

Hopefully this will get you down the right path.

answered on Stack Overflow Sep 9, 2010 by llasram
0

PROCESS_VM_READ is not enough: Try use both PROCESS_VM_WRITE + PROCESS_VM_OPERATION. I also received an error violation but the process memory still changed. Add try catch to keep your program alive.

PROCESS_VM_READ = 0x0010
PROCESS_VM_WRITE = 0x0020
PROCESS_VM_OPERATION = 0x0008
PROCESS_ALL_ACCESS = 0x1F0FFF

For me PROCESS_VM_WRITE was not enough, I needed to add PROCESS_VM_OPERATION as well.

answered on Stack Overflow Apr 21, 2018 by Staked • edited Apr 21, 2018 by Staked

User contributions licensed under CC BY-SA 3.0