0

我又一次面临着对我的代码进行轻微修改的挑战,以适应一些编写不佳的代码的不可修改的库。

经过数小时的研究(在发现您无法将任何类型的状态传递给函数指针之后),我需要在将 EAX 重置为 0xCCCCCCCC 的函数头中删除 ASM 字节。

通过使用内置的 VC++ 调试器获取函数的“地址”并在作弊引擎中手动创建一个字节数组(这对这类事情非常有用),它成功提取了字节,我可以 NOP 5字节序列手动。

但是,以编程方式执行此操作有点不同。

当我执行以下任何操作时,地址明显高于调试器报告的地址,这给了我一个指向错误字节的指针。

unsigned int ptr = reinterpret_cast<unsigned int>(testhack);
unsigned char* tstc = (unsigned char*)&testhack;
FARPROC prc = GetProcAddress(GetModuleHandle("mod.dll"), "testhack"); // Still
                    // returns the incorrect address (same as the previous two)

调试器在做什么来找到正确的地址?如何以编程方式找到正确的地址?

4

2 回答 2

1

大概函数地址在 DLL 中。在这种情况下,您所看到的是加载程序将例如的地址重新定位到加载程序&testhack的内存的正确位置。调试器可能已经知道重定位,并且会自动为您处理这些问题,允许您修改字节。

不幸的是,我不知道有任何机制可以解决这个问题,但是如果你静态链接地址将在链接时而不是运行时固定。

于 2012-08-16T18:49:58.450 回答
0

弄清楚了。

完全忘记了(我相信被称为)查找表。我收到的地址是指向查找表条目的指针,它是一个简单的 5 字节无条件 JMP,指向真正的函数体。我所要做的就是获取偏移量,将其添加到查找表条目的末尾,然后我就有了正确的地址。

这是到达函数正确起始地址的代码。

// Get the lookup table address
const char* ptr = (const char*)&testhack;
// Get the offset (+ 1 byte retrieved as a long)
unsigned int offset = (unsigned int)(*((unsigned int*)(ptr + 1)));
// Add to the original look up pointer, +5 (the offset starts after the
//    end of the instruction)
const char* tst = (const char*)(ptr + offset + 5);

tst然后持有正确的地址!

到目前为止,调用 ASM 指令将指向包含函数指针的结构的指针放入 EAX。通常,回调函数会重置 EAX。但是,我已经应用了这个 hack 并且 NOP 删除了那部分。函数内的第一行代码创建一个本地指针,然后内联汇编mov [ptr],eax将地址放入指针中。然后我可以正常使用指针。

于 2012-08-16T18:55:03.310 回答