我再一次面临着我的代码中的轻微破解的挑战,以适应一些编写糟糕的代码的不可修改的库。
经过数小时的研究(在发现你无法将任何类型的状态传递给函数指针之后),我需要NOP输出函数头中的ASM字节,将EAX重置为0xCCCCCCCC。
通过使用内置的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)
调试器找到正确的地址是做什么的?如何以编程方式找到正确的地址?
答案 0 :(得分:1)
据推测,函数地址在DLL中。在这种情况下,您所看到的是加载程序将例如&testhack
的地址重定位到加载程序的内存的正确位置。调试器可能已经知道重定位并且有助于自动为您处理,允许您修改字节。
不幸的是我不知道有任何机制可以解决这个问题,但是如果静态链接,地址将在链接时而不是运行时修复。
答案 1 :(得分:0)
想出来。
完全忘记了(我相信所谓的)查找表。我收到的地址是查找表条目的指针,它是 real 函数体的一个简单的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。但是,我已经应用了这个黑客和NOP那个部分。函数内的第一行代码创建一个本地指针,然后将内联汇编到mov [ptr],eax
的地址转换为指针。然后我可以正常使用指针。