0

我敢肯定这是一个非常奇怪的问题,但相信我,它有道理。我在 GameMaker 语言中有一个值数组,我希望能够在数组中搜索数组边界之外的值,并检索这些超出边界的值,而不是返回错误并停止游戏。基本上,在使用越界索引搜索数组时,我想故意从附近的内存中提取不正确的数据。这可能吗?先感谢您!

4

1 回答 1

1

但相信我,这有道理

最好提及您为什么要做某事,以便如果无法做到,可以在没有后续问题的情况下给出建议。

GameMaker 不允许无效的内存访问(外来错误除外),尽管即使允许,也会有更多问题 - 如果您检查 YYGML.h(在运行时目录中),GML 值由 表示struct RValue,即 16 -byte 结构,由 8 个值字节(如数值、字符串指针、数组指针等)、值类型索引和元数据标志组成。换句话说,尝试将任意内存作为 GML 值读取是行不通的,因为类型和标志都是垃圾,当您点击指向无效内存的指针类型值时,很可能会导致运行时因访问冲突而崩溃地点。

如果你想在你的进程中读取任意内存,你可以编写一个本地扩展(通常在 C++ 中),它带有一个函数,该函数接受一个缓冲区地址(来自buffer_get_address)、起始地址和长度,通过调用VirtualQuery(验证内存区域是否可访问并检索边界),然后memcpy

此类函数的非 GML 特定实现可能如下所示:

bool safeCopy(byte* out, const byte* from, size_t size) {
    const auto pmask = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE |
        PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
    auto at = from;
    auto till = at + size;
    ::MEMORY_BASIC_INFORMATION mbi{};
    while (at < till) {
        if (!VirtualQuery(at, &mbi, sizeof mbi)) return false;
        if ((mbi.State == MEM_COMMIT) && !(mbi.Protect & PAGE_GUARD) && (mbi.Protect & pmask)) {
            const byte* m_begin = static_cast<const byte*>(mbi.BaseAddress);
            const byte* m_end = m_begin + mbi.RegionSize;
            at = m_end;
            if (m_end > till) m_end = till;
            if (m_begin < from) m_begin = from;
            memcpy(out + (m_begin - from), m_begin, m_end - m_begin);
        } else return false;
    }
    return true;
}
于 2020-12-21T10:26:49.130 回答