Python ctypes long integer error, how can i fix this?

87 views Asked by At

I am developing memory snapshot / acquisition software with Python, so I use the "pymem_snapshot" library and "winpmem" driver.

import ctypes
import struct
import sys
import win32file
import win32service
import os
from ctypes import *


def CTL_CODE(DeviceType, Function, Method, Access):
    return (DeviceType << 16) | (Access << 14) | (Function << 2) | Method
    
CTRL_IOCTRL = CTL_CODE(0x22, 0x101, 3, 3) # IOCTL_SET_MODE
INFO_IOCTRL = CTL_CODE(0x22, 0x103, 3, 3)
IOCTL_REVERSE_SEARCH_QUERY = CTL_CODE(0x22, 0x104, 3, 3)

class PyMem:
    FIELDS = (["CR3", "NtBuildNumber", "KernBase", "KDBG"] +
              ["KPCR%02d" % i for i in range(32)] +
              ["PfnDataBase", "PsLoadedModuleList", "PsActiveProcessHead"] +
              ["Padding%s" % i for i in range(0xff)] +
              ["NumberOfRuns"])
    
    def GetInfo(fd):
        result = win32file.DeviceIoControl(fd, INFO_IOCTRL, b"", 102400, None)
        fmt_string = "Q" * len(PyMem.FIELDS)
        memory_parameters = dict(zip(PyMem.FIELDS, struct.unpack_from(fmt_string, result)))
        for k, v in sorted(memory_parameters.items()):
            if k.startswith("Pad"):
                continue
            if not v: continue
            print("%s: \t%#08x (%s)" % (k, v, v))

    def SetMode(fd, modeset = "pte"):
        try:
            if modeset == "iospace":
                mode = 0
            elif modeset == "physical":
                mode = 1
            elif modeset == "pte":
                mode = 2
            elif modeset == "pte_pci":
                mode = 3
            else:
                raise RuntimeError("Mode %s not supported" % str(modeset))
            win32file.DeviceIoControl(fd, CTRL_IOCTRL, struct.pack("I", mode), 0, None)
            print(f"Mode has been set to {modeset}")
        except Exception as e:
            return str(e)
    
    def service_create():
        try:
            os.system(f"net stop winpmem")  # Stop any previous instance of the driver
            os.system(f"sc delete winpmem")  # Delete any previous instance of the driver
            if ctypes.sizeof(ctypes.c_voidp) == 4:
                if os.path.isfile("winpmem_x86.sys") is True:
                    driver_path = "winpmem_x86.sys"
                else:
                    return "Driver file are not found"
            else:
                if os.path.isfile("winpmem_x64.sys") is True:
                    driver_path = "winpmem_x64.sys"
                else:
                    return "Driver file are not found"
            # Create a new instance of the driver
            driver = os.path.join(os.getcwd(), driver_path)
            hScm = win32service.OpenSCManager(None, None, win32service.SC_MANAGER_CREATE_SERVICE)
            try:
                hSvc = win32service.CreateService(hScm, "winpmem", "winpmem", win32service.SERVICE_ALL_ACCESS, win32service.SERVICE_KERNEL_DRIVER, win32service.SERVICE_DEMAND_START, win32service.SERVICE_ERROR_IGNORE, driver, None, 0, None, None, None)
            except win32service.error as e:
                print(e)
                hSvc = win32service.OpenService(hScm, "winpmem", win32service.SERVICE_ALL_ACCESS)
                
            try:
                win32service.ControlService(hSvc, win32service.SERVICE_CONTROL_STOP)
            except win32service.error:
                pass

            try:
                win32service.StartService(hSvc, [])
            except win32service.error as e:
                print("%s: will try to continue" % e)

            print("WinPMEM Started")
        except Exception as e:
            print("ERROR : WinPMEM can not created. Reason : " + str(e))

    @staticmethod
    def dump_and_save_memory(filename, memsize = int(1024 * 1024)):
        print("Creating AFF4 (Rekall) file")
        device_handle = win32file.CreateFile(
            "\\\\.\\pmem",
            win32file.GENERIC_READ | win32file.GENERIC_WRITE,
            win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE,
            None,
            win32file.OPEN_EXISTING,
            win32file.FILE_ATTRIBUTE_NORMAL,
            None)
        # Set Modes and get informations
        if device_handle is True:
            print("Error: open device failed.\n")
        else:
            PyMem.SetMode(device_handle)
            PyMem.GetInfo(device_handle)
            print("\nMEMSIZE : " + str(memsize))
            with open(filename + ".aff", "wb") as f:
                mem_addr = 0
                while mem_addr < memsize:
                    win32file.SetFilePointer(device_handle, mem_addr, 0) # Setting pointer
                    data = win32file.ReadFile(device_handle, memsize)[1] # Reading memory...
                    f.write(data) # Writing to file
                    mem_addr += memsize
                    offset_in_mb = mem_addr / 1024 / 1024
                    if not offset_in_mb % 50:
                        sys.stdout.write("\n%04dMB\t" % offset_in_mb)
                    sys.stdout.flush()
                    print(f"Dumped {mem_addr} / {memsize} bytes and {offset_in_mb} MB/offset ({mem_addr * 100 / memsize:.2f}%)")
                f.close()
                win32file.CloseHandle(device_handle)

If you want class GitHub link

But when I want to get large size memory (more than 2GB) I get integer error.

My program (stable)

from src.pymem_class import PyMem

if __name__ == "__main__":
    PyMem.service_create()
    # Drivers: https://github.com/Velocidex/WinPmem/tree/master/kernel/binaries
    # Run "bcdedit /set testsigning on" command
    # Check Memory Compression with "Get-MMAgent" command
    # Disable Memory Compression with "Disable-MMAgent -mc" command
    # Restart computer
    PyMem.dump_and_save_memory("demo", int(1024 * 1024 * 1024)) # 1 GB Memory Image WORKING

My program (crash)

from src.pymem_class import PyMem

if __name__ == "__main__":
    PyMem.service_create()
    # Drivers: https://github.com/Velocidex/WinPmem/tree/master/kernel/binaries
    # Run "bcdedit /set testsigning on" command
    # Check Memory Compression with "Get-MMAgent" command
    # Disable Memory Compression with "Disable-MMAgent -mc" command
    # Restart computer
    PyMem.dump_and_save_memory("demo", int(8 * 1024 * 1024 * 1024)) # 8 GB Memory Image CRASH

Crash logs

Traceback (most recent call last):
  File "C:\Users\dfnss\OneDrive\Desktop\pymem_snapshot\example.py", line 11, in <module>
    PyMem.dump_and_save_memory("demo", memsize)
  File "C:\Users\dfnss\OneDrive\Desktop\pymem_snapshot\src\pymem_class.py", line 51, in dump_and_save_memory
    data = win32file.ReadFile(device_handle, memsize)[1] # Reading memory...
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Second param must be an integer or writeable buffer object

How can I fix this? I even tried help from ChatGPT but it didn't work

Thanks for answers

1

There are 1 answers

3
Schnitte On

Pymem expects an integer number (of int) type as a parameter for the memory size. The int data type on Python ranges from -2,147,483,648 to + 2,147,483,647 (source: enter link description here). This means that your equation 1024 * 1024 * 1024 is within this range, but 8 * 1024 * 1024 * 1024 isn't.