2

我目前正在记忆编辑一款名为 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;
}

我认为这比我写的更难看。我不建议你阅读它,除非你想偏头痛。

4

2 回答 2

2

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

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

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

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

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

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

#define PTR_ADD( PTR, OFFSET ) \
   (((char *)(PTR)) + (OFFSET))
于 2013-04-27T22:13:38.157 回答
1

自从您发布此内容以来,我们已将 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。

于 2020-01-02T00:38:29.837 回答