Python Ctypes Read/WriteProcessMemory() — Ошибка 5/998 Помогите!

Пожалуйста, не пугайтесь, но следующий код, если вы знакомы с ctypes или C, должен быть легко читаем.

Я так долго пытался заставить мои функции ReadProcessMemory() и WriteProcessMemory() работать, и перепробовал почти все возможности, кроме правильного.

Он запускает целевую программу, возвращает ее PID и работает нормально. Но я всегда получаю код ошибки 5 - ERROR_ACCESS_DENIED. Когда я запускаю функцию чтения (забудьте сейчас о записи). Я запускаю эту программу как дочерний процесс с PROCESS_ALL_ACCESS или CREATE_PRESERVE_CODE_AUTHZ_LEVEL.

Я также пробовал PROCESS_ALL_ACCESS и PROCESS_VM_READ, когда открываю дескриптор.

Я также могу сказать, что это правильное место в памяти, потому что я могу найти его в работающей программе с помощью CheatEngine.

Что касается VirtualQuery(), я получаю код ошибки 998 - ERROR_NOACCESS, что еще раз подтверждает мое подозрение, что это какая-то проблема с безопасностью/привилегиями.

Любая помощь или идеи будут очень признательны, опять же, это пока вся моя программа, пусть вас это не пугает =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)

Спасибо!


person Community    schedule 23.03.2010    source источник


Ответы (5)


Вы должны попытаться установить привилегии отладки для вашего процесса. Используйте следующий код один раз, прежде чем пытаться открыть/создать процесс.

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 )
person Pagefault    schedule 11.03.2011

Возможно, это поможет вам: Создание дескриптора безопасности для Новый объект в C++

person sbelieve    schedule 05.06.2010

Одной из возможных причин ошибки отказа в доступе является то, что пользователь, под которым вы запускаете WriteProcessMemory, должен иметь привилегию DEBUG.

Начиная с Vista, эта привилегия активируется только для администраторов и только при запуске приложения с параметром «Запуск от имени администратора».

Вы можете добавить привилегию к любой учетной записи.

person Meh    schedule 03.04.2010

Я вижу несколько проблем с вашим кодом, и трудно понять, какая из них является основной причиной именно вашей проблемы. Например, строка:

address = raw_input('Enter and address: ')

Вероятно, должно быть что-то вроде:

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

Как видно из кода, каждый раз, когда вы передаете address функции через ctypes, вы на самом деле создаете временный буфер, который содержит именно строку, введенную пользователем, и передаете адрес этого буфера в процесс Python. Определенно не то, что вы хотите. Если я решу эту проблему, ваша программа будет работать большую часть времени.

Из моего ограниченного тестирования большинство (все?) остальных сбоев можно исправить, установив правильный argtypes для ReadProcessMemory. Это самая большая проблема, которую я вижу в коде ctypes, проблема усугубляется обработкой ctypes.c_voidp как int в Python. Если argtypes не указано, то все аргументы считаются ctypes.c_int. Все, что выходит за пределы диапазона целого числа со знаком — например, указатель или дескриптор с установленным старшим битом — автоматически усекается.

Не причиной ваших ошибок, а неоптимальными являются строки:

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

Модуль ctypes предоставляет функции для создания буферов:

bufferSize = 32
buffer = ctypes.create_string_buffer(bufferSize)

Надеюсь, это направит вас по правильному пути.

person llasram    schedule 09.09.2010

PROCESS_VM_READ недостаточно: попробуйте использовать оба PROCESS_VM_WRITE + PROCESS_VM_OPERATION. Я также получил нарушение ошибки, но память процесса все еще изменилась. Добавьте try catch, чтобы сохранить вашу программу в рабочем состоянии.

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

Мне не хватило PROCESS_VM_WRITE, нужно было еще добавить PROCESS_VM_OPERATION.

person Staked    schedule 21.04.2018