Python Ctypes Read / WriteProcessMemory () - Ошибка 5/998 Справка! - PullRequest
1 голос
/ 23 марта 2010

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

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

Он запускает целевую программу, возвращает ее PID и обрабатывает просто отлично. Но я всегда получаю код ошибки 5 - ERROR_ACCESS_DENIED. Когда я запускаю функцию чтения (пока забудь запись). Я запускаю эту программу как процесс, который, по моему мнению, является процессом CHILD с 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)

Спасибо!

Ответы [ 5 ]

2 голосов
/ 11 марта 2011

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

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 )
1 голос
/ 05 июня 2010
0 голосов
/ 21 апреля 2018

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.

0 голосов
/ 09 сентября 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)

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

0 голосов
/ 03 апреля 2010

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

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

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

...