Как получить базовый адрес процесса с помощью MODULEENTRY32?

Я хочу что-то сделать в этом примере: Python - Как получить начальный/базовый адрес процесса?. У меня та же проблема, что и у человека в этой теме, в том, что механизм читов указателей ссылается на базовый адрес самого процесса.

Я осмотрелся, и похоже, что лучшим решением является использование ctypes и MODULEENTRY32 для хранения моментальных снимков процессов и анализа их modBaseAddr.

Вот мой текущий код

import os.path, ctypes, ctypes.wintypes
from ctypes import *
from ctypes.wintypes import *

PROCESS_QUERY_INFORMATION = (0x0400)
PROCESS_VM_OPERATION = (0x0008)
PROCESS_VM_READ = (0x0010)
PROCESS_VM_WRITE = (0x0020)
TH32CS_SNAPMODULE = (0x00000008)

CreateToolhelp32Snapshot= ctypes.windll.kernel32.CreateToolhelp32Snapshot
Process32First = ctypes.windll.kernel32.Process32First
Process32Next = ctypes.windll.kernel32.Process32Next
Module32First = ctypes.windll.kernel32.Module32First
Module32Next = ctypes.windll.kernel32.Module32Next
GetLastError = ctypes.windll.kernel32.GetLastError
OpenProcess = ctypes.windll.kernel32.OpenProcess
GetPriorityClass = ctypes.windll.kernel32.GetPriorityClass
CloseHandle = ctypes.windll.kernel32.CloseHandle

class MODULEENTRY32(Structure):
       _fields_ = [ ( 'dwSize' , DWORD ) , 
                ( 'th32ModuleID' , DWORD ),
                ( 'th32ProcessID' , DWORD ),
                ( 'GlblcntUsage' , DWORD ),
                ( 'ProccntUsage' , DWORD ) ,
                ( 'modBaseAddr' , POINTER(BYTE)) ,
                ( 'modBaseSize' , DWORD ) , 
                ( 'hModule' , HMODULE ) ,
                ( 'szModule' , c_char * 256 ),
                ( 'szExePath' , c_char * 260 ) ]



def GetBaseAddr(ProcId, ProcName):
       me32 = MODULEENTRY32()
       me32.dwSize = sizeof(me32)
       hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcId)
       if GetLastError() != 0:
              CloseHandle(hSnapshot)
              print 'Handle Error %s' % WinError()
              return 'Error'

       else:
              if Module32First(hSnapshot, byref(me32)):
                     if me32.szModule == ProcName:
                            CloseHandle(hSnapshot)
                            return id(me32.modBaseAddr)

                     else:
                            Module32Next(hSnapshot, byref(me32))
                            while int(GetLastError())!= 18:
                                   if me32.szModule == ProcName:
                                          CloseHandle(hSnapshot)
                                          return id(me32.modBaseAddr)

                                   else:
                                          Module32Next(hSnapshot, byref(me32))

                            CloseHandle(hSnapshot)
                            print 'Couldn\'t find Process with name %s' % ProcName

              else:
                     print 'Module32First is False %s' % WinError()
                     CloseHandle(hSnapshot)

def GetProcessIdByName( pName):
       if pName.endswith('.exe'):
              pass
       else:
              pName = pName+'.exe'

       ProcessIds, BytesReturned = EnumProcesses()

       for index in range(BytesReturned / ctypes.sizeof(ctypes.wintypes.DWORD)):
              ProcessId = ProcessIds[index]
              hProcess = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId)
              if hProcess:
                     ImageFileName = (ctypes.c_char*MAX_PATH)()
                     if ctypes.windll.psapi.GetProcessImageFileNameA(hProcess, ImageFileName, MAX_PATH)>0:
                            filename = os.path.basename(ImageFileName.value)
                            if filename == pName:
                                   return ProcessId
                     CloseHandle(hProcess)

def EnumProcesses():
       count = 32
       while True:
              ProcessIds = (ctypes.wintypes.DWORD*count)()
              cb = ctypes.sizeof(ProcessIds)
              BytesReturned = ctypes.wintypes.DWORD()
              if ctypes.windll.Psapi.EnumProcesses(ctypes.byref(ProcessIds), cb, ctypes.byref(BytesReturned)):
                     if BytesReturned.value<cb:
                            return ProcessIds, BytesReturned.value
                            break
                     else:
                            count *= 2
              else:
                     return None



if __name__ == '__main__':
       ProcId = GetProcessIdByName('RocketLeague.exe')
       #print ProcId
       print hex(GetBaseAddr(ProcId, 'RocketLeague.exe'))
       #print hex(GetBaseAddr(8252,'RocketLeague.exe'))

Теперь мое понимание памяти не самое лучшее, но я полагаю, что базовый адрес должен быть статическим во время работы программы. Когда я запускаю этот код, ModBaseAddr, который я получаю, меняется каждый раз, когда я его запускаю. Еще одна странная проблема, с которой я сталкиваюсь, заключается в том, что без этого оператора печати ProcId запуск программы возвращает ERROR_ACCESS_DENIED (ошибка 5) из строки 41 (это как-то связано с функцией CreateToolhelp32Snapshot, я предполагаю, что у меня есть права администратора на компьютере). Однако с оператором печати программа каждый раз выдает мне другой ModBaseAddr. Если я передаю функции GetBaseAddr ProcessId вручную, она также работает без оператора печати, но опять же, она каждый раз дает мне случайный адрес. Если бы кто-нибудь мог оказать мне любую помощь или указать мне в правильном направлении, я бы очень признателен!


person Garrett Jones    schedule 13.10.2016    source источник


Ответы (1)


Уточнение: MODULEENTRY32 хранит информацию о модулях, а не о процессах. при вызове CreateToolhelp32Snapshot с помощью TH32CS_SNAPMODULE вы получаете модули, загружаемые процессом, а не самими процессами.

Вместо получения MODULEENTRY32 в сочетании с EnumProcesses вы можете вместо этого использовать CreateToolHelp32Snapshot с помощью TH32CS_SNAPPROCESS, чтобы получить список процессов в виде PROCESSENRTY32, которые также содержат идентификатор процесса.

Несмотря на то, что вы являетесь пользователем с правами администратора, вы также должны запускать процесс от имени администратора.

Вы также должны убедиться, что вы инициализируете свой MODULEENTRY32 в {0} для правильной обработки ошибок и не сталкиваетесь с проблемой, когда возвращаемое значение зависит от неопределенного поведения неинициализированной памяти.

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

def ListProcessModules( ProcessID ):
    hModuleSnap = c_void_p(0)
    me32 = MODULEENTRY32()
    me32.dwSize = sizeof( MODULEENTRY32 )
    hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, ProcessID )

    ret = Module32First( hModuleSnap, pointer(me32) )
    if ret == 0 :
        print 'ListProcessModules() Error on Module32First[%d]' % GetLastError()
        CloseHandle( hModuleSnap )
        return False 

    while ret :
        print "   MODULE NAME:     %s"%             me32.szModule 
        print "   executable     = %s"%             me32.szExePath 
        print "   process ID     = 0x%08X"%         me32.th32ProcessID 
        print "   ref count (g)  =     0x%04X"%     me32.GlblcntUsage 
        print "   ref count (p)  =     0x%04X"%     me32.ProccntUsage 
        print "   base address   = 0x%08X"%         me32.modBaseAddr 
        print "   base size      = %d"%             me32.modBaseSize 

        ret = Module32Next( hModuleSnap , pointer(me32) )

    CloseHandle( hModuleSnap )
    return True
person GuidedHacking    schedule 23.07.2019