예제 #1
0
def read_protected_addr(mbi, address, num_bytes):
    """read a number of bytes from a given protected memory address. The access
    flags will be changed temporarily and then be restored afterwards.
    @param mbi: Memory basic information, obtained by read_addr
    @type mbi: MEMORY_BASIC_INFORMATION
    @param address: address to read from
    @type address: int
    @param num_bytes: Number of bytes to read from that address
    @type num_bytes: int
    @return: bytes read
    """
    mbi = defines.MEMORY_BASIC_INFORMATION()
    KERNEL_32.VirtualQuery(address, byref(mbi), sizeof(mbi))
    base = mbi.BaseAddress
    size = mbi.RegionSize
    old_protect = mbi.Protect
    new_protect = defines.PAGE_EXECUTE_READWRITE
    old_protect_dummy = defines.DWORD(0)

    logging.warning("[read_addr] Memory: Protection override!")
    KERNEL_32.VirtualProtect(base, size, new_protect, byref(old_protect_dummy))
    mem_buffer = ctypes.create_string_buffer(num_bytes)
    ctypes.memmove(ctypes.addressof(mem_buffer), address, num_bytes)
    KERNEL_32.VirtualProtect(base, size, old_protect, byref(old_protect_dummy))
    return mem_buffer.raw
예제 #2
0
def read_addr(address, num_bytes):
    """read a number of bytes from a given memory address. The function
    will try to override existing access rights to read from 
    the specified memory location anyway.
    @param address: address to read from
    @type address: int
    @param num_bytes: Number of bytes to read from that address
    @type num_bytes: int
    @return: bytes read
    """

    mbi = defines.MEMORY_BASIC_INFORMATION()
    if KERNEL_32.VirtualQuery(address, byref(mbi), sizeof(mbi)) != sizeof(mbi):
        logging.warning("[read_addr] could not read from given address")
        return ""

    if (mbi.State != defines.MEM_COMMIT):
        logging.warning("[read_addr] Memory: State != MEM_COMMIT for addr " \
                        "0x%08x (is 0x%08x)!", address, mbi.State)
        return ""

    elif (mbi.Protect & 0x100) == 0x100:
        logging.warning("[read_addr] Trying to access a guard page at " \
                        "address 0x%08x. Skipping memory operation", address)
        return ""

    elif (mbi.Protect & 0xe6) == 0:
        mem = read_protected_addr(mbi, address, num_bytes)
        return mem

    else:
        mem_buffer = ctypes.create_string_buffer(num_bytes)
        mem_buffer_addr = ctypes.addressof(mem_buffer)
        ctypes.memmove(mem_buffer_addr, address, num_bytes)
        return mem_buffer.raw
예제 #3
0
def set_executable(address, size):
    """set executable flag for a subsequent number of bytes beginning at
    given address.
    @param address: address of first byte to set executable
    @type address: int
    @param size: number of bytes to set executable
    @type size: int
    """
    mbi = defines.MEMORY_BASIC_INFORMATION()
    if KERNEL_32.VirtualQuery(address, byref(mbi), sizeof(mbi)) != sizeof(mbi):
        logging.error("VirtualQuery: Failed to get memory info")
        return False

    if mbi.Protect >= 0x10:
        return True  #already executable

    new_protect = mbi.Protect << 4  # add EXEC
    old_protect = defines.DWORD(0)
    if not KERNEL_32.VirtualProtect(address, size, new_protect,
                                    byref(old_protect)):
        logging.error("Cannot set address 0x%08x to executable" %\
                      address)
        return False

    return True
예제 #4
0
def get_region_information(address):
    """Return start and size of the region in which the address belongs. This
    consists of a range of pages that are commited together.
    @param address: Memory address to get the region for
    @type address: int
    @return: tuple consisting of (start, size) of region or C{None} if address
    not committed
    """
    mbi = defines.MEMORY_BASIC_INFORMATION()
    if ctypes.windll.kernel32.VirtualQuery(address, byref(mbi),
                                           sizeof(mbi)) != sizeof(mbi):
        return None

    if not (mbi.State & defines.MEM_COMMIT):
        return None

    return (mbi.BaseAddress, mbi.RegionSize)
예제 #5
0
def write_mem(address, data):
    """Write data to address. Data is either written completely, no error
    occurs on any of the bytes or not written at all.
    @param address: Memory address to write data to
    @type address: int
    @param data: data to write
    @type data: str
    @return: C{True} on success, C{False} on failure
    """

    data_len = len(data)

    #FIXME: memmove throws exception - no need to check using virtualquery
    #       speeds up but may throw exception in program
    #       -> other exception handler?
    chk_addr = address
    chk_len = data_len
    while chk_len > 0:
        mbi = defines.MEMORY_BASIC_INFORMATION()
        if KERNEL_32.VirtualQuery(address, byref(mbi),
                                  sizeof(mbi)) != sizeof(mbi):
            logging.debug("VirtualQuery: Failed to get memory info")
            return False

        if (mbi.State != defines.MEM_COMMIT):
            logging.error("Cannot write to %x - protected with flags %x" % \
                          (address, mbi.Protect))
            return False
        if mbi.Protect & 0xcc == 0:
            #logging.warn("Writing to address 0x%08x not allowed - using " \
            #             "aggressive writing" \
            #             % address)
            return write_mem_aggressive(address, data)

        bytes_in_page = (mbi.BaseAddress + mbi.RegionSize) - chk_addr
        chk_len -= bytes_in_page
        chk_addr += bytes_in_page

    # all data can be written to writeable pages - fine :)

    temp_buf = ctypes.create_string_buffer(data, len(data))
    ctypes.memmove(address, temp_buf, len(data))

    return True