我目前正在编辑一款名为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;
}
我认为这比我写的更糟糕。除非你想要偏头痛,否则我不建议你阅读它。
答案 0 :(得分:2)
我不确定“最干净的方式”,但除了取消引用这些指针外,你无能为力。我建议使用typedefs
只是为了让您的代码更具可读性。
另外,请不要担心将int *
投射到int **
。当然它被认为是“不好的做法”,但如果你知道你在做什么,它可能正是所需要的。你必须要小心。
typedef int *** intPtr3;
typedef int ****** intPtr6;
您还可以使用一些宏来清理语法。这将是智能地使用宏来提高可读性和清洁度并减少错误机会的一个很好的例子:
#define DEREF6( PTR ) \
******(PTR)
最后,我经常使用一个很好的宏来将指针移动到内存中的字节数量:
#define PTR_ADD( PTR, OFFSET ) \
(((char *)(PTR)) + (OFFSET))
答案 1 :(得分:0)
自从您发布此信息以来,我们已将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兼容。