Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

ctypes CreateToolhelp32Snapshot падает с ERROR_PARTIAL_COPY

ctypes
Теги: #<Tag:0x00007f7b658b3660>

(Artur Korobeynyk) #1

Есть два питона 2.7 (х32 и х64). Ещё есть один тестовый бинарник, собраный под х32 (гарантировано х32).
Питон запускает этот собраный бинарник так:

    if kernel32.CreateProcessA(path_to_exe,
                            None,
                            None,
                            None,
                            None,
                            creation_flags,
                            None,
                            None,
                            byref(startupinfo),
                            byref(process_information))

После этого идет некоторый код и далее я пытаюсь получить снепшот хендл на используемые в процессе подключаемые библиотеки:

def my_func_resolve(self, dll, function):
    module32 = MODULEENTRY32()
    module32.dwSize = sizeof(MODULEENTRY32)
    CreateToolhelp32Snapshot = kernel32.CreateToolhelp32Snapshot
    CreateToolhelp32Snapshot.restype = HANDLE
    CreateToolhelp32Snapshot.argtypes = [DWORD, DWORD]
    Module32First = kernel32.Module32First
    Module32First.restype = BOOL
    Module32First.argtypes = [HANDLE, POINTER(MODULEENTRY32)]
    Module32Next = kernel32.Module32Next
    Module32Next.restype = BOOL
    Module32Next.argtypes = [HANDLE, POINTER(MODULEENTRY32)]
    kernel32.CloseHandle.restype = BOOL
    kernel32.CloseHandle.argtypes = [HANDLE]
    is64 = BOOL(False)
    if not kernel32.IsWow64Process(self.h_process, byref(is64)):
        print "Failed to check IsWow64Process. Error: %d" % kernel32.GetLastError()
    print "Process is 64 bits: %s" % str(is64.value)
    print "Python is 64 bits: %s" % str(sys.maxsize > 2**32)
    thandle = 24
    while thandle == 24:
        thandle = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, self.pid)
    if thandle == 2**32 - 1 or thandle == 2**64 - 1:
        print "Failed to create a snapshot. Error: %d" % kernel32.GetLastError()
        exit()
    if not Module32First(thandle, byref(module32)):
        print "Module32First failed (module handle is 0x%08x). Error: %d" % (thandle, kernel32.GetLastError())
        kernel32.CloseHandle(thandle)
        exit()
    while module32:
        Module32Next(thandle, byref(module32))
        print "DLL %s is loaded at 0x%08x" % (module32.szModule, module32.modBaseAddr)
    kernel32.CloseHandle(thandle)
    return True

Используя питон х32 и х64 получаю один результат: CreateToolhelp32Snapshot возвращает INVALID_HANDLE_VALUE с ошибкой ядра ERROR_PARTIAL_COPY.
Кратко о двух проблемах здесь:

  1. Почему 32 битный питон процесс на 64 битной ос запускает 32 битный ехе и из этого получается 64 битный процесс?
  2. Почему код не работает даже на 64 битном питоне, который по идее должен вмещать все структуры 64 битной ОС?

Коллекция платиновых вопросов AT INFO и список решений
(Artur Korobeynyk) #2

Update: По первому вопросу:
IsWow64Process возвращает True и для 64 битных процессов. Это означает что процесс использует эмуляцию винда 32 в винде 64.
Update2: my_func_resolve вроде отработает правильно. Баг где -то в createprocess. Скрипт не состоянии получить доступ к таблице импортов в момент вызова. Слипы не помогают. Creation_flags = DEBUG (0x1)


(Artur Korobeynyk) #3

CreateProcess вызывался с флагом DEBUG_PROCESS, который суспендил основной поток процесса при возникновении дебажного ивента (а их генерируется дофига при запуске). Для того чтобы продолжить процесс надо вызывать ContinueDebugEvent функцию и парсить следующий ивент. И так до тех пор, пока не подгрузится адрессная таблица загружаемых библиотек. После этого можно делать снепшот и перечислять подгруженые модули.