【问题标题】:What is the cleanest way to dereference multi-level pointers with offsets?用偏移量取消引用多级指针的最简洁方法是什么?
【发布时间】:2013-04-21 20:03:28
【问题描述】:

我目前正在记忆编辑一款名为 Assault Cube 的游戏。不幸的是,由于动态内存分配,每次游戏开始时,我要编辑的值的地址都会发生变化。幸运的是,有些静态指针总是指向动态地址。使用作弊引擎,我可以找到指针,但它们有时会达到 8 级。而不是每次都做********pointer,我宁愿做:*pointer。最重要的是,它们有偏移量,所以硬编码它们将是一场噩梦。

相反,我使用的是这个函数:

int* getLowestPointer(int** highestPointer, int levels, int offsets[])
{
    for (int i = 0; i < levels; i++) {
        highestPointer = (int**) (*highestPointer + offsets[i]/sizeof(int)); // I am dividing by sizeof(int) here to undo pointer arithmetic (since the offsets are the difference between the offsetted pointer and the base pointer - not in integer increments)
    }
    return (int*) highestPointer;
}

但它非常混乱,我将 int* 转换为 int** ,反之亦然,这被认为是不好的做法。有什么我可以做的不会导致不良做法的事情吗?我也在网上找到了这个:

DWORD FindDmaAddy(int PointerLevel, DWORD Offsets[], DWORD BaseAddress)
{
    DWORD Ptr = *(DWORD*)(BaseAddress);
    if(Ptr == 0) return NULL;

    for(int i = 0; i < PointerLevel; i ++)
    {
        if(i == PointerLevel-1)
        {
            Ptr = (DWORD)(Ptr+Offsets[i]);
            if(Ptr == 0) return NULL;
            return Ptr;
        }
        else
        {
            Ptr = *(DWORD*)(Ptr+Offsets[i]);
            if(Ptr == 0) return NULL;
        }
    }
    return Ptr;
}

我觉得比我写的还要丑。除非您想偏头痛,否则我不建议您阅读。

【问题讨论】:

  • 考虑到我想不出更好的要求。我提出的唯一建议是使用char*char** 指针。那么你就不需要/sizeof(int),你就能正确处理不是sizeof(int)倍数的偏移量。
  • 请说明这不违反版权、作弊或以其他方式不道德。
  • @brianbeuning; Assaultcube 是开源的,所以它可能不会侵犯版权。编写游戏秘籍是了解内存模型、asm 和补丁等知识的绝佳方式。
  • Rich 一针见血。

标签: c pointers reverse-engineering memory-editing


【解决方案1】:

我不确定“最干净的方式”,但除了取消引用这些指针之外,您无能为力。我建议使用typedefs 只是为了让您的代码更具可读性。

也不必担心将int * 转换为int **。当然这被认为是“不好的做法”,但如果你知道你在做什么,它可能正是需要的。你只需要小心。

typedef int *** intPtr3;
typedef int ****** intPtr6;

您还可以使用一些宏来清理您的语法。这将是智能地使用宏来提高可读性和简洁性并减少错误机会的一个很好的例子:

#define DEREF6( PTR ) \
  ******(PTR)

最后,我经常使用一个很好的宏来将指针移动到内存中的字节数:

#define PTR_ADD( PTR, OFFSET ) \
   (((char *)(PTR)) + (OFFSET))

【讨论】:

【解决方案2】:

自从您发布此内容后,我们已将 FindDMAAddy 更改为更简洁,现在看起来像这样

uintptr_t FindDMAAddy(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{
    for (unsigned int i = 0; i < offsets.size(); ++i)
    {
        ReadProcessMemory(hProc, (BYTE*)ptr, &ptr, sizeof(ptr), 0);
        ptr += offsets[i];
    }
    return ptr;
}

几行代码,无需手动定义长度,只要你的构建类型与目标进程的架构相匹配,就可以兼容 x64。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 2010-09-08
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    相关资源
    最近更新 更多