【问题标题】:Enforce VirtualAlloc address less than 32-bits on 64-bit machine在 64 位机器上强制 VirtualAlloc 地址小于 32 位
【发布时间】:2020-08-18 18:27:39
【问题描述】:

我需要在内存中分配一定的空间,为此我一直使用VirtualAlloc。 然而,我越来越注意到VirtualAlloc 返回一个超过 32 位的地址,尽管总是小于 33 位。 结果就是当我把数据复制到这个内存地址的时候,电脑就死机了。

我正在使用 64 位 Windows 和 64 位 Python。我怀疑将数据复制到内存的程序只能处理 32 位。有没有办法强制VirtualAlloc 提供 32 位内的地址?

我正在使用Python,特别是ctypes 包来调用VirtualAlloc,请参见下面的代码。 多次执行此代码会更改地址,因此重复调用下面的函数最终会导致地址低于 32 位。但是,我正在寻找问题的原因和故障安全解决方案。任何帮助将不胜感激。

import ctypes
mem_commit = 0x1000
page_readwrite = 0x4
size_bytes = 200000  # Allocation sizes are usually around this value

ctypes.windll.kernel32.VirtualAlloc.argtypes = [
    ctypes.c_void_p, ctypes.c_long, ctypes.c_long, ctypes.c_long]
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_int

addr = ctypes.windll.kernel32.VirtualAlloc(
    0, ctypes.c_long(size_bytes), mem_commit, page_readwrite)    

请注意,我之后使用 VirtualFree 释放了内存。

【问题讨论】:

  • 我认为崩溃是由于您传递给“内存复制功能”的addr 中包含的截断值。见this answer

标签: python memory ctypes kernel32 virtualalloc


【解决方案1】:

只要在此范围内有足够的可用空间,就可以从 32 位地址内存开始使用 VirtualAlloc 强制执行内存分配。查看msdoc,我们有以下函数签名:

LPVOID VirtualAlloc(
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD  flAllocationType,
  DWORD  flProtect
);

以及lpAddress的以下描述:

要分配的区域的起始地址[...]如果该参数为NULL,则系统确定分配区域的位置。

所以你可以用这个参数选择地址。在您的情况下,您为 lpAddress 指定了 0,它被视为 NULL 值。

此外,您必须考虑,如果您选择内存地址,您必须确保空间是空闲的,否则VirtualAlloc 不会给您空间。

此外,您使用 mem_commit 而不使用 mem_reserve 并且 msdoc 说:

尝试通过指定 MEM_COMMIT 而不指定 MEM_RESERVE 和非 NULL lpAddress 来提交特定地址范围会失败,除非整个范围已被保留。

更好的选择是将 0x3000 (MEM_COMMIT|MEM_RESERVE) 用于flAllocationType

最后,您当然可以使用 64 位地址,但您将 VirtualAlloc 的结果类型设置为 c_int,在 Windows 上,这是带符号的 32 位 c_long 的别名。因此VirtualAlloc 返回的 64 位地址将被截断,因此您将使用错误的地址来复制数据。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 2011-02-05
    • 1970-01-01
    • 2011-08-08
    • 2011-04-09
    • 2011-06-26
    • 1970-01-01
    相关资源
    最近更新 更多